Infosys Microsoft Alliance and Solutions blog

« December 2007 | Main | February 2008 »

January 31, 2008

Working with MSMQ Journal Queues

In one of our internal forums, recently, someone had posted a query regarding issues in connecting and receiving messages from journal queues. The exception they were getting was "Queue ID is not registered in DS". I hadn't worked with Journal queues before, but this error seemed to me to be related to the queue path.

In my earlier blogs (here and here), I had discussed about the importance of specifying the right name for the queue and also mentioned how the path will typically look like. I decided to give it a try and created a private queue on my local machine and enabled journaling on it. Enabling journaling is as trivial as checking a checkbox in the queue property window.  You can also enable it by setting the UseJournalQueue property on the message.

Having done this, I used the syntax as described on MSDN Documentation.

            MessageQueue queue = new MessageQueue(".\\test\\journal$");

To my surprise, I got an exception stating "A workgroup installation computer does not support the operation." Well, it isn't really a surprise, since this syntax is for public queues and that's what the error message is also indicating. The following are the various syntaxes that did work for me. You could use either of the following based on your own preferences.  Note that the "test" in the queue path is name of the private queue that i created.

            MessageQueue queue = new MessageQueue(".\\private$\\test\\journal$");

            MessageQueue queue = new MessageQueue(".\\private$\\test;journal");

The casing for "journal" doesn't matter and you can very well specify it as "JOURNAL". So much for local private queue. I quickly tried accessing the journal queue for a remote private queue as well, and following worked for me

            MessageQueue queue = new MessageQueue("FormatName:DIRECT=OS:server\\private$\\remote;journal");

Where "server" is the remote machine name. Again, "journal" can be specified as "JOURNAL" as well. The following, though is an extension of what worked in case of local private queue, didn't work for remote private queue and I got a "Format name is invalid" exception.

            MessageQueue queue = new MessageQueue("FormatName:DIRECT=OS:punhjw30076\\private$\\remote\\journal$");

January 30, 2008

Hierarchical Data Categorization using LINQ to Objects in n-tier applications

The intention here is not to talk about LINQ; rather to apply LINQ in enterprise applications. A typical n-tier application consists of Presentation, Business/Service and Data layer and the communication across the layers is done through Presentation, Services/Business, Data entities. We write translator classes which maps the Data entities to their corresponding Service entities and so on. This is fine as long as the mapping is one to one. The problem arises when we have store procedures (SP) returning composite entities. The situation gets complicated when we have to parse the composite entity returned from SPs into a hierarchical parent-child structure. With LINQ to Objects this task is very much simplified.

I will try to illustrate this with an example. I have two business entities Category and SubCategory.

public class Category

{

    public int Id {get;set;}       

    public List<SubCategory> SC {get;set;} //SubCategory is the child object of category

}

 

public class SubCategory

{

    public int Id {get;set;}

    public string Name {get;set;}

}

 

Output from the SP in my Data Access Layer is combination of the above entities.

A sample output from the SP:

CategoryID

SubCategoryID

SubCategoryName

1

1

“SC1”

1

2

“SC2”

1

3

“SC3”

1

4

“SC4”

2

1

“SC5”

2

2

“SC6”

3

1

“SC7”

4

1

“SC8”

Let me assume the result is stored in an entity which maps the output. Let me call this RecordCategory

public class RecordCategory

{

    public int Id {get;set;}       

    public int SId {get;set;}

    public string SName {get;set;}

}

 

The job now is to convert the rows of records into a hierarchial data struture correspoding to Category-SubCategory entities i.e. every CategoryID should coresspond to s single Catehory object with a list of SubCategory objects having the same CategoryID.

Here is how this is done:

List<RecordCategory> rc = new List<RecordCategory>();

//rc = Retrieve data from SP

//Group the records retrieved form the SP on their

//Category Id using the group by query operattor

IEnumerable<IGrouping<int,RecordCategory>> cat = from p in rc

                                    group p by p.Id;

 

The data will be grouped hierarchially.But the business layer expects a list of Catgeory objects along with SubCategory data.

List<Category> cat1 = (from c in cat                           

    select new Category {Id = c.Key,Name = c.First().Name, SC =

        (

            from d in c

            where d.Id == c.Key

                select new SubCategory{Id = d.SId,Name=d.SName}

            ).ToList()

    }).ToList();//Return the cat1 object to BAL

 

All we are doing here is running a nested query to group all the SubCategory object inside the Category object.

We could have achieved the same result without using LINQ – but then we had to resort to endless for loops and conditions.This is how elegant our code can get using LINQ!!.

January 28, 2008

Branding in SharePoint Technologies (PART 4)

Today we will look at the option of Site Definitions and Features for modifying the Master Pages.

Site Definitions: As the name suggests, site definitions has all the required information for provisioning a site. There are different site definitions, for different purposes, which are used to provision sites. All site definition files (including the master pages) are stored on the file system; unlike, the site templates that are stored in the content database.
The process to create new site definitions for custom branding is outside the scope of this article. Following is a brief outline of the process:
1.Site definitions are located at <Drive:>\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\SiteTemplates.
2.Copy the desired definition with the name of the custom site definition
3.Change the WEBTEMP XML file with the addition of the configuration node in the templates node for the custom site definition located at the location as shown in Figure 6: Location of the WEbTemp*.xml files. The display category takes care of the tab in which it appears when a person tries to create it through the UI. For more information on the templates and their respective entries, see  http://www.sharepointblogs.com/photos/tbaginski/images/2552/original.aspx.
Note: IIS Reset needs to be done for the changes to get effected and the new site definition to appear during the site creation process.

There are two issues with this approach:
•This requires good understanding of xml files which are used for provisioning the sites. The files include onet.xml and webtemp*.xml files
If OOTB templates are modified then MS technical support will not support them. One needs to be very careful while editing any OOTB site definitions.
•The best alternative is to create a clone of a similar site definition, and edit it to meet the template requirements.
•Sites can be created using any template within a Web Application. This calls for having a one-to-one mapping for all the OOTB templates, in a way to ensure that the end users/administrators use only these templates to create the site. This calls for the discipline during the web application creation. Using OOTB template will result in branding inconsistencies as that will just have the default branding.
 

Features: ‘Features’ is a concept introduced in SharePoint to increase the modularity of the functionality/ elements developed on it. Functionalities like custom workflow, event handlers, copying files, etc can be handled using features. They are highly modular, componentized, can be applied to any site at any level within a Web Application. They can be automatically activated and deactivated.
Using this concept, the master pages for a given site collection is packaged into a feature and applied so that it is copied to the respective gallery and is applied automatically. It is not mandatory to apply the feature automatically. The administrator can apply the master page of choice by browsing through the gallery at any time. A classic OOTB example for this is the ‘SharePoint Server Publishing Infrastructure’ feature which adds master page to the gallery.

Note: Master Pages should be copied to the site collection master page gallery as the SharePoint Look and Feel option in the site settings always refer to this gallery when the admin browses to change the master page

The process to create new function is outside the scope of this article. Following is a brief outline of the process ((The sample will have all the required things so that the end user can customize and start using it) :

1.Create a folder under <Drive>\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES with the name of the feature
2.Place the required .css files, master pages, images required etc in this location
3.Script both the Feature and the elements manifest files
4.Make sure the master pages go to the master page gallery and the other resources go to the style gallery. Sample of this looks like

<Elements xmlns=”http://schemas.microsoft.com/sharepoint/”>
    <Module Name=”CustomMasterPage” Url=”_catalogs/masterpage” RootWebOnly=”TRUE”>      
        <File Url=”CustomPage.master” Type=”GhostableInLibrary” />  
    </Module>
    <Module Name=”CustomStyles” Url=”Style Library” RootWebOnly=”TRUE”>      
        <File Url=”Custom.css” Type=”GhostableInLibrary” />  
        <File Url=”HeaderImage.jpg” Type=”GhostableInLibrary” />  
</Module>
</Elements>

There are different options available both for the module element and the file elements (that is outside the scope of this document).
5.Once this feature is installed using the stsadm utility the master pages and the resource files will become available in their respective gallery.
6.Now this feature can be automatically activated to apply it using another feature called staper feature (The feature discussed above is called the staplee feature). For more information about defining this feature, see http://blogs.msdn.com/sharepoint/archive/2007/03/22/customizing-moss-2007-my-sites-within-the-enterprise.aspx
Note: In addition to deploying the pages into the gallery, features can also be used to deploy the pages into the file system which effectively means that pages can be deployed into site definitions as well.

The following table gives the broad guidance on the scenarios and relevant options.

Creating Multiple Versions of Workflows

In the recent past, a question that has surfaced quite often is regarding the versioning of workflows and the errors that show up when trying to do so. It is quite natural to expect an extreme level of dynamism and out-of-box features from Microsoft, but one needs to take a pragmatic view of WF.

There is a clear distinction between a Workflow Definition and a Workflow Instance. A Workflow Definition is a Template and a Workflow Instance is a runtime representation of that template. We can closely relate to the Workflow Definition and a Workflow Instance to a Class and an object respectively.

A Workflow can be authored programmatically in C# or exclusively in XAML or using a combination of both. When a workflow instance is created and persisted, it is persisted with its state and also the type information of workflow and activities used. During this cycle of instance passivation, if the definition of the workflow (or the activity used in the workflow) is changed and the assembly with the old definition is removed, then the workflow runtime throws an error. This is an expected behavior since Binary Serialization is type dependent.

Workflow Foundation does have a solution to this problem in the form of Dynamic Workflow Updates using the WorkflowChanges API. The following is one of the possible ways of mitigate the problem of workflow versioning:

1. The assembly with the new workflow definition (or activity definition) is added to the GAC (or a location where you reference your assemblies from). This will sit beside the assembly (older version) that contained the older definition. The assembly with the older definition(s) MUST be present in the GAC (or a location where you reference your assemblies from).

2. When the workflow is to be rehydrated, identify the changes between the older definition and newer definition by getting hold of the corresponding definitions and apply changes to the workflow using the WorkflowChanges API.  Once the changes are done, the workflow can be resumed. Two ways in which this can be done:

- This can be done on-demand or can be a background process. When we say on-demand, the applying of changes is done when the workflow is rehydrated by the user or application and it is resumed immediately.

- If it is a background process, the workflow instances corresponding to this workflow can be loaded into the memory; changes can be applied and the instances can be dehydrated back to the persistence store. So, when the workflow instance is next invoked by the application, it is loaded and resumed directly. This process can be accomplished using a windows service. However, the synchronization aspect should be taken care of here.

But the question definitely remains as to why there isn't a mechanism which can change the instances when there is a change to the definition of the workflow? Here is one possible reason:

A defintion is a "Stateless" entitiy while an instance has a "State". A workflow definition is either a .NET assembly or an XAML file which is used to create an instance. Any change to the definition means a change to the stateless entity and it happens at design-time. To get this reflected on to a run-time entity needs a program to do so. Moreover, the Workflow Persistence Service can be customized and this makes it an even greater challenge.

For a small set of workflows, the issue of versioning may not really be a show stopper. However, when planning a large scale use of WF, it is necessary to take an appropriate view of the versioning required and move ahead. It is important to set the expectations right before dealing with situations like these.Smile

Enterprise Collaboration - Role of Technology

Lately, there has been a lot of buzz on collaboration and how it is becoming important for rapid innovation especially in a globally distributed and culturally diverse business environment. Technology is being seen as an important enabler and catalyst for collaboration. Enterprises are viewing technology usage from different perspectives to enhance and address different aspects of collaboration.

I tend to group these into 3 perspectives: 

1. Information Perspective - Make it easy to find and share information

Most large enterprises have teams spread in several geographies. Finding information and managing shared information is becoming increasingly difficult. Most of these organizations are recognizing the need for an enterprise wide information management strategy that takes into account not just structured but unstructured data as well. If most of the documents in your enterprise are being shared using emails irrespective of number of recipients and it's hard to find information when you need it, I think you know what I am talking about.

Movement of large platform vendors and increased adoption of collaborative information management tools like Microsoft SharePoint Server is a clear indication that enterprise are taking this aspect of collaboration quite seriously. From a Microsoft point of view, this has enabled them to move from a successful information worker tools provider into the Information Management space.

2. Communication Perspective - Make it easy to express and communicate effectively

I often feel the need to walk up to the person and express myself, especially when the problem or idea is not well defined or still in conceptualization phase. With distributed teams, effective communication of ideas\problems etc is an important aspect of collaboration. Depending on factors like the number of people I am communicating with, the time zone factor, urgency level and complexity of the message, I would like to use different set of communication tools. While a plethora of tools are already available for communication in most enterprises, the disjointed manner it which these are being made available is impacting adoption (after the initial excitement). Clearly, there is need to deliver enhanced communication capabilities in an integrated and synchronized manner.

Several enterprises are already laying foundations for this through a variety of technology initiatives like VoIP enablement, messaging upgrades, integrated presence, mobility etc. However, the human aspects or the experience aspects of these still being neglected due to which a lot of money\effort is likely to be spent after the deployment in trying to make people use the technology. Clearly, there is a need to focus on human and experience aspects early and take a unified people or role oriented approach for such initiatives.

Microsoft, which has already large deployments of Exchange and Messaging software and a popular mobile platform, is investing heavily the unified communication area. These are still early days and it will be interesting to watch in what direction does the market moves.


3. People Perspective - Make it easy to find people and connect with them

One of the other aspects that people in global enterprises are struggling with is "finding the right people" and connecting with them. Most of the tools or applications are tuned to finding and managing people you already know. With talent distributed across the several locations and several people on the move, it is often hard to find the right people at the right time.  Networking opportunities like company meetings, coffee breaks, hallway conversations are also limited. However, a few enterprises are realizing how important networking opportunities are, for not just sharing and ideation, but even for executing day to day work. They are already experimenting with enterprise social networking sites to help people from different locations to "get to know" each other and establish a level of trust which is fundamental for collaboration.

As far as enterprise collaboration technologies are concerned, we are still in early days. Collaboration is an important aspect for doing business in the flat world and role of technology will become increasingly important especially in the global context. I believe that eventually, global enterprises will need to address collaboration from all the 3 perspectives - information, communication and people in an integrated fashion to realize the foundations of a "true collaboration platform".

Custom User Input Validation in WPF

Building any application that works with User Input cannot be complete usually without having some sort of validations for the input values. WPF is no exception. There is an interesting discussion around WPF validation on Paul Stovell's blog

Martin Bennedik has written a WPF Validation Block over Microsoft's Enterprise Library 3.0. WPF 3.5 also brings in additional validation support via the IDataEffortInfo Interface.

However, all said and done, these techniques typically work with data binding. One can always work with Data binding in WPF, but what if you don't have a need for that? What if there are say only one or two fields you want to validate? Also the WPF validation does provide feedback to the user when validation fails by using the ErrorTemplate, but to mark some field as mandatory, one typically still requires to be put the most used red asterix (*) near the mandatory fields.

Look at the screen shot of an application below. It has two text boxes for user's first name and last name. Both are mandatory. However instead of the asterix approach, I thought of why not the text box itself show a red border when it is empty and also a tooltip along with it to show what is required. Once the user enter's a valid value, the border can change back to the default border color. Finally, the text boxes also should be queriable for valid state so that when the form/dialog/window is submitted, I can loop through them and see if I can submit or not.

ValidationApp.jpg

First, to see how to have the TextBox check and provide feedback on it being valid. For this I used the new Extension Method functionality in C# 3.0. For a deep dive into this feature, check here. The following is the method I wrote where I just check to see if the TextBox control has some string entered or not and return true/false accordingly. Needless to say that the TextBox in the parameter below is from the System.Windows.Controls namespace, that is used in WPF.

    public static class CustomExtensions

    {

        public static bool IsValid(this TextBox obj)

        {

            if (obj.Text.Length > 0)

                return true;

 

            return false;

        }

    }

Next, to display the appropriate borders, I needed two brush resources - one, the default border brush that the TextBox uses and, two, a similar gradient brush that fills to red color to be used when the TextBox is invalid. Creating these with Expression Blend is very trivial. I saved these both as resources in the XAML file.

    <Window.Resources>

        <LinearGradientBrush x:Key="FaultyBorderBrush" EndPoint="0,20" StartPoint="0,0" MappingMode="Absolute">

            <GradientStop Color="#FFABADB3" Offset="0.05"/>

            <GradientStop Color="#FFE2E3EA" Offset="0.07"/>

            <GradientStop Color="#FFFF0000" Offset="1"/>

        </LinearGradientBrush>

        <LinearGradientBrush x:Key="DefaultBorderBrush" EndPoint="0,20" StartPoint="0,0" MappingMode="Absolute">

            <GradientStop Color="#FFABADB3" Offset="0.05"/>

            <GradientStop Color="#FFE2E3EA" Offset="0.07"/>

            <GradientStop Color="#FFE3E9EF" Offset="1"/>

        </LinearGradientBrush>

    </Window.Resources>

Finally, comes the logic to invoke the IsValid method at appropriate times so that the necessary feedback can be given to the user. The initial setting was done in the constructor of the Window so that i could initially show the TextBoxs with red border and the tooltip (as shown in the figure above). I also handled the TextChange event of the TextBoxes so that I could invoke the IsValid method to see if the TextBox is valid or not and change the border color appropriately. I also handled the Button's click event just to show that while submitting the form, I can invoke the same method and allow/prevent submission of the form accordingly. The following code shows the complete code behind for the Window.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

 

namespace GenericWPFApp

{

    /// <summary>

    /// Interaction logic for MainPane.xaml

    /// </summary>

    public partial class MainPane : Window

    {

        const string _firstNameMessage = "FirstName cannot be left blank";

        //following is used with the different extension method which supports min and max lengths

        const string _lastNameMessage = "LastName should be between 0 and 100 characters";

 

        public MainPane()

        {

            InitializeComponent();

 

            //since the text boxes are initially empty, they are invalid. Initialize them accordingly

            SetTextBoxProperties(txtFirstName, false, _firstNameMessage);

            SetTextBoxProperties(txtLastName, false, _lastNameMessage);

        }

 

        private void txtFirstName_TextChanged(object sender, TextChangedEventArgs e)

        {

            TextBox box = sender as TextBox;

            if (box != null)

                SetTextBoxProperties(box, box.IsValid(), _firstNameMessage );

        }

 

        private void txtLastName_TextChanged(object sender, TextChangedEventArgs e)

        {

            TextBox box = sender as TextBox;

            if (box != null)

                SetTextBoxProperties(box, box.IsValid(0, 100), _lastNameMessage);

        }

 

        private void SetTextBoxProperties(TextBox ctrl, bool valid, string tip)

        {

            if (valid)

            {

                ctrl.BorderBrush = (Brush)TryFindResource("DefaultBorderBrush");

                ctrl.ToolTip = null;

            }

            else

            {

                ctrl.BorderBrush = (Brush)TryFindResource("FaultyBorderBrush");

                ctrl.ToolTip = tip;

            }

        }

 

        private void Button_Click(object sender, RoutedEventArgs e)

        {

            bool valid = false;

            valid = txtFirstName.IsValid();

            if (!valid)

            {

                message.Text = "Form is invalid";

                return;

            }

 

            valid = txtLastName.IsValid(0, 100);

            if (!valid)

            {

                message.Text = "Form is invalid";

                return;

            }

 

            message.Text = "Form is valid";

        }

    }

}

Disclaimer: The code isn't optimized and you may find better ways to implement the same logic. I just wanted to show that we can get some of the validation functionality without necessarily going the DataBinding way. Another caveat is that since the extension method is written for the TextBox, it will be available for all the TextBoxes used in the application. While this is good, the issue could be that you may want different logic for different TextBoxes. You can always write different implementations for the same. One such method, which works with minimum and maxium length is shown below. The challenge however will be to invoke the right method for the appropriate TextBoxes.

        public static bool IsValid(this TextBox obj, int minLen, int maxLen)

        {

            int length = obj.Text.Length;

            if ((minLen < length)  && (maxLen > length))

                return true;

 

            return false;

        }

Since extension methods can be written for any control/class, you can write similar logic for any WPF control to provide your own validation mechanisms. Comments welcome !  

 

 

 

 

January 25, 2008

Object-Relational Mapping(Part-I)

There has always been a debate on how to represent data in an application and how it should be persisted in a backend RDBMS. Why can't there be a uniform methodology for both? It has been an eternal debate but we have to live with the fact that data is represented using object-oriented methodology within an application where as it is stored in the RDBMS in accordance with the relational theory. The inherent differences between these two approaches can be attributed to the fact that the underlying methodologies, i.e. Object-Oriented and Relational theories are based on sofware-engineering and mathematical principles respectively. And the difference in the way data is represented in relational and object-oriented world is termed as object-relational impedance mismatch.

In a series of articles, I will discuss the impedance mismatch problem, some of the approaches to solve it and a few most widely used Object-Relational Mapping frameworks. In this article we will try to understand the fundamental characteristics of these two systems.

Object Systems
Characteristics of an Object model can be defined by four basic parameters: identity, state, behavior and encapsulation. The most important parameter in my point of view is identity because it is implicit to the object itself, in other words every object is uniquely identified by its identity irrespective of its state which means even if two objects have same state, they are still different and distinct. They may be similar or equivalent or a mirror image of each other but they are distinctly represented in memory. Behavior is basically a set of operations user can invoke to interact or manipulate the object. Encapsulation prevents user from reading and modifying the internal details of the object. Other important characteristics like inheritance, polymorphism, association, type etc can be derived from the above mentioned basic parameters.

Relational Systems
Relational model is completely based on predicate logic and set theory. The word Relation is used synonymously with Table in a database model contrary to the popular belief that relation is a link between different tables on the basis of some keys. Characteristics of a relational model is defined by relation, attribute, tuple, relation value and relation variable [Date 95]. A relation is a truth predicate having a set of attributes that gives some meaning to the predicate.

For example, we can define a relation "Customer" as {Customer ID, Name, Address, City, State, Zip} There exists a Customer with a Customer ID who has a Name and lives at an address specified by Address, City, State and Zip.
Attributes are statement of facts about the relation and ordering of attributes are not specified in a relation.
A tuple is a truth statement in context of a relation containing attribute values which map the required attributes in the relation. For example,

<Customer Customer ID="100001", Name="Farrukh Nizami", Address="Mehdipatnam", City="Hyderabad", State="AP", Zip="500028">

Two tuples are considered identical if their corresponding relation and attribute values are also identical. The ordering of attribute values is immaterial.
A relation value consists of a relation and a set of tuples that match the relation and a relation variable is a placeholder for a given relation and can change value with time. Therefore, inside an insurance company, a relation variable PolicyHolder can be written to hold the relation Customer and consist of the relation value

{ <Customer Customer ID="100001", Name="Farrukh Nizami", Address="Mehdipatnam", City="Hyderabad", State="AP", Zip="500028">
<Customer Customer ID="100002", Name="Kishore Gopalan", Address="BTM Layout", City="Bangalore", State="KN", Zip="560034>
<Customer Customer ID="100003", Name="Noor Mohammed", Address="Tollichowki", City="Hyderabad", State="AP", Zip="500028">
}


Commonly used words for these are Table (Relation Variable), Rows (Tuples), Columns (Attributes) and a collection of relation variables is called Database. These basic characteristics are combined against one another with the help of some operators like join, union, intersection etc. to form the basis for SQL. The use of operators allow us to create derived relation variables which are relations that are created from other relation values in the database.

Already you can see the difference in the way the two worlds view the system. I will elaborate these differences in the next article, so keep watching this space for more on Object-Relational Mapping concepts.

January 24, 2008

Better business decision making with Performance Point Server 2007

Recent days there are lot of competitions floating around the business world. One is struggling to make an effective business decision with the data they have in their enterprise. But just having data is not going to help improving your business, all you need is 'Information'. How one can make use of these information to achieve what they are looking for? Microsoft provides set of business intelligence tools to deliver a holistic approach to convert business information into actionable insight by providing an integrated platform for analyzing & monitoring enterprise performance metrics and planning your business. Microsoft Office Performance Point Server 2007(Commonly Known as PPS) is one such tool which allows one to identify the KPIs, maps those KPIs with various business metrics, build scorecards, reports and dashboards.

 

Performance Point Server is built on top of SQL Server 2005. It has two components
1.     Dashboard Designer
2.     Planning Business Modeler


Dashboard Designer:

A dashboard is a collection of graphs, reports, and Key Performance Indicators that can help you monitor your business. The following components are available in the dashboard designer

1.     Data Source - Analysis Services, ODBC, Excel Services, Excel 2007, SharePoint Lists, SQL Server table
2.     KPI - Blank KPIs, KPIs import from Analysis Services
3.     Scorecards - Blank Scorecard, Analysis Services, Fixed value, Excel Services, Excel 2007, SharePoint Lists, SQL Server table
4.     Reports - Analytic chart, Analytic Grid, Excel Services, Pivot chart, Pivot table, ProClarity Analytic server page, SQL Server report, Strategy map, Trend analysis chart, web page
5.     Indicators - Variety of indicators available to highlight the performance of different metrics. One can also have custom indicators 

Creating dashboard is the simplest task with PPS. Al you need to do is drag and drop the required Scorecards, reports and filters and position them as per your need. Finally the dashboard can be published to a SharePoint Portal (MOSS 2007 & SPS 2003) using simple navigational screens.  

Planning Business Modeler:

Microsoft Office PerformancePoint Server 2007 can help you drive consistency throughout your organization, span planning needs across your enterprise, extend your investments in Microsoft, and provide every employee with a stake in the corporate performance management process.

Office PerformancePoint Server 2007 makes it easy to:

  • Import data from multiple sources, including multiple general ledger systems.
  • Easily feed data automatically into a centralized, trusted data store.
  • Embed standardized business rules and processes.
  • Provide everyone with a single interface.
  • Ensure that people only see appropriate and relevant information.
  • Track changes automatically.
  • Manage planning and budgeting processes.


PerformancePoint Server 2007 delivers on these goals first by utilizing Microsoft Office Excel as the end-user interface for planning, budgeting, and forecasting. With PerformancePoint Server 2007, Excel is where people contribute, interact, and build reports. And Excel is where end users ultimately write their changes back to a central data model that contains data on actual side-by-side with planning data.

PerformancePoint Server 2007 data models are built to support the range of business models used in your organization, from sophisticated financial modeling to straightforward budget planning.

Built on top of the proven enterprise capabilities of Microsoft SQL Server 2005, PerformancePoint Server 2007 ensures that your performance management application can scale to meet a large user base.

Importance of Application.DoEvents

Recently a colleague of mine shared a code that he was working on where he was playing around with Asynch ADO.NET. He had a simple WinForm application. On the click of a button, he was making calls to the DB to get data. To try out the asynch features, he had introduced delays in the code.

The code looked something like below

        private void button1_Click(object sender, EventArgs e)

        {

            //start with empty text boxes and these get populated once the DB query returns

            textBox1.Text = string.Empty;

            textBox2.Text = string.Empty;

            textBox3.Text = string.Empty;

 

            SqlCommand com1 = null; SqlCommand com2 = null; SqlCommand com3 = null;

            SqlConnection con1 = null; SqlConnection con2 = null; SqlConnection con3 = null;

            SqlDataReader dr1 = null; SqlDataReader dr2 = null; SqlDataReader dr3 = null;

            string str1 = string.Empty;

 

            try

            {

                string connection = "Data Source=.;Asynchronous Processing=true;Initial Catalog = pubs;Integrated Security=True";

                con1 = new SqlConnection(connection);

                con1.Open();

                com1 = new SqlCommand("SELECT * FROM authors", con1);

 

                con2 = new SqlConnection(connection);

                con2.Open();

                com2 = new SqlCommand("waitfor delay '00:00:05';SELECT * FROM authors", con2);

 

                con3 = new SqlConnection(connection);

                con3.Open();

                com3 = new SqlCommand("waitfor delay '00:00:10';SELECT * FROM authors", con3);

 

                IAsyncResult ar1 = com1.BeginExecuteReader();

                IAsyncResult ar2 = com2.BeginExecuteReader();

                IAsyncResult ar3 = com3.BeginExecuteReader();

 

                WaitHandle[] handles = new WaitHandle[3];

                handles[0] = ar1.AsyncWaitHandle;

                handles[1] = ar2.AsyncWaitHandle;

                handles[2] = ar3.AsyncWaitHandle;

 

                for (int results = 0; results < handles.GetLength(0); results++)

                {

                    // wait for any handle, then process results as they come

 

                    int index = WaitHandle.WaitAny(handles, -1, false); // infinite secs

                    //depending on which call completed, update the appropriate text box

                    if (index == 0)

                    {

                        dr1 = com1.EndExecuteReader(ar1);

                        while (dr1.Read())

                        {

                            str1 = str1 + dr1[0] + " " + dr1[1] + " " + dr1[2] + "\n";

                        }

                        textBox1.Text = str1;

                    }

                    else if (index == 1)

                    {

                        dr2 = com2.EndExecuteReader(ar2);

                        while (dr2.Read())

                        {

                            str1 = str1 + dr2[0] + " " + dr2[1] + " " + dr2[2] + "\n";

                        }

                        textBox2.Text = str1;

                    }

                    else if (index == 2)

                    {

                        dr3 = com3.EndExecuteReader(ar3);

                        while (dr3.Read())

                        {

                            str1 = str1 + dr3[0] + " " + dr3[1] + " " + dr3[2] + "\n";

                        }

                        textBox3.Text = str1;

                    }

                }

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message);

            }

            finally

            {

                con1.Close();

                con2.Close();

                con3.Close();

            }

        }

Is this the best code that could be written is debatable. One could write separate handlers to handle the completion of each of the Asynch queries. But that's not the point. Let's for the sake of argument assume there is a specific need to have written the code in this manner. When you run this code, you would get some unexpected results

1. If after return of all 3 queries, you click the button again, you would expect the text boxes to clear up and then get filled up again when the queries  return after 5 and 10 secs. But that doesn't happen and the text boxes don't seem to clear up.

2. Each time you re-run the application, the way in which the results get populated in the text boxes is unpredictable. Sometimes, it will appear to work find while in most cases, the data for all three text boxes gets displayed at one shot (essentially after the last query has also returned)

So what's happening here? If you have experience only with the current .net programming only, it will be difficult to understand. Those of you who have programmed for Windows applications using the Win32 APIs directly like say with Visual C++ 1.5 or 2.0 or even with MFC would recall some of the key concepts there

1. Windows relies heavily on messaging infrastructure. Actions on the windows/controls etc generate messages that the code handles by picking messages from a queue and then passing them to a windows procedure. While processing of a message is happening, other messages will wait in the queue to be picked up.

2. The messages in the queue have different priorities. Those with higher priority even if come in while some messages are already in the queue, will get pushed foward and will be processed before the low priority messages.

3. The visual rendering of windows and controls there-in happens by processing the WM_PAINT message. During the processing of this message, the code uses the device context provided to it (which is usually the display device context) and draws the contents on it, which show up on the desktop display

4. Each time a control is invalidated (property change) like say text is entered into a text box, it needs to redraw itself so that it can show the currently set text. This is done by calling a Win32 API to invalidate itself, which causes a WM_PAINT message to be posted to the message queue. When the application gets a chance to process the message, the text box will update itself and show the new text.

The key to the issue with the above code is related to all these points with specific focus on the last point. In the sample code above, the text box has been updated by setting its Text property. It would have in turn generated a WM_PAINT message, but since the code above is in a loop, it essentially doesn't allows the processing of the message queue and hence the WM_PAINT message isn't processed on time.

It is in such scenarios that the Application.DoEvents API is useful. As you would see in the documentation, it mentions that a call to this allows Windows to immediately process all messages in the queue. So if we add this  call at appropriate places (as shown below in bold face), the behavior of the UI will be more in line with what we expect. 

        private void button1_Click(object sender, EventArgs e)

        {

            //start with empty text boxes and these get populated once the DB query returns

            textBox1.Text = string.Empty;

            textBox2.Text = string.Empty;

            textBox3.Text = string.Empty;

            Application.DoEvents();

 

            SqlCommand com1 = null; SqlCommand com2 = null; SqlCommand com3 = null;

            SqlConnection con1 = null; SqlConnection con2 = null; SqlConnection con3 = null;

            SqlDataReader dr1 = null; SqlDataReader dr2 = null; SqlDataReader dr3 = null;

            string str1 = string.Empty;

 

            try

            {

                string connection = "Data Source=.;Asynchronous Processing=true;Initial Catalog = pubs;Integrated Security=True";

                con1 = new SqlConnection(connection);

                con1.Open();

                com1 = new SqlCommand("SELECT * FROM authors", con1);

 

                con2 = new SqlConnection(connection);

                con2.Open();

                com2 = new SqlCommand("waitfor delay '00:00:05';SELECT * FROM authors", con2);

 

                con3 = new SqlConnection(connection);

                con3.Open();

                com3 = new SqlCommand("waitfor delay '00:00:10';SELECT * FROM authors", con3);

 

                IAsyncResult ar1 = com1.BeginExecuteReader();

                IAsyncResult ar2 = com2.BeginExecuteReader();

                IAsyncResult ar3 = com3.BeginExecuteReader();

 

                WaitHandle[] handles = new WaitHandle[3];

                handles[0] = ar1.AsyncWaitHandle;

                handles[1] = ar2.AsyncWaitHandle;

                handles[2] = ar3.AsyncWaitHandle;

 

                for (int results = 0; results < handles.GetLength(0); results++)

                {

                    // wait for any handle, then process results as they come

 

                    int index = WaitHandle.WaitAny(handles, -1, false); // infinite secs

                    //depending on which call completed, update the appropriate text box

                    if (index == 0)

                    {

                        dr1 = com1.EndExecuteReader(ar1);

                        while (dr1.Read())

                        {

                            str1 = str1 + dr1[0] + " " + dr1[1] + " " + dr1[2] + "\n";

                        }

                        textBox1.Text = str1;

                        Application.DoEvents();

                    }

                    else if (index == 1)

                    {

                        dr2 = com2.EndExecuteReader(ar2);

                        while (dr2.Read())

                        {

                            str1 = str1 + dr2[0] + " " + dr2[1] + " " + dr2[2] + "\n";

                        }

                        textBox2.Text = str1;

                        Application.DoEvents();

                    }

                    else if (index == 2)

                    {

                        dr3 = com3.EndExecuteReader(ar3);

                        while (dr3.Read())

                        {

                            str1 = str1 + dr3[0] + " " + dr3[1] + " " + dr3[2] + "\n";

                        }

                        textBox3.Text = str1;

                  Application.DoEvents();

                    }

                }

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message);

            }

            finally

            {

                con1.Close();

                con2.Close();

                con3.Close();

            }

        }

A quick look into the .net code us