synBoogaloo - BizTalk/.Net 3.0

Why is it drug addicts and computer afficionados are both called users?

  Home  |   Contact  |   Syndication    |   Login
  28 Posts | 0 Stories | 26 Comments | 119 Trackbacks

News

Archives

Post Categories

Image Galleries

Blog Role

Organisations

Photo Album

Wednesday, June 20, 2007 #

Simon an architect I work with was talking to a developer this morning. The conversation went as so…

 

Simon: Are you sure you want to use FTP to transfer this data I’m not sure it will be fast enough

Developer: Well FTP is faster than TCPIP

Simon (to himself): I have now entered the twilight zone

 


Wednesday, April 25, 2007 #

We finally got an EJB Web Service today from a Trading Partner the interface looked something like this ...

public Asset ReturnAsset(bool ReturnAsset)

We surmised that due to cronic shortages of quality developers they have finally begun to teach chimpanzees Java, not bad for a chimp.

Also liked this newsgroup thread Simon found yesterday... 


Tuesday, April 17, 2007 #

A new online BizTalk mag has come out, a more pleasent read than most whitepapers, especially if you're a motor head or a fan of that Ministry song.


I just noticed that in GeeksWithBlogs move to SubText some of my old screen shots have been lost, I'll fix these as soon as I get time.

We are developing BizTalk applications with Visual Studio Team Edition and every now and then for some reason the Orchestration Designer is removed from the "Open With" dialog, thus when one double clicks on an orchestration it is opened with the Xml Editor. Although I'm not sure why this happens, I suspected the items in this dialog were configured in the Windows Registry ... and so they were, so to fix:

1) Open RegEdit
2) Go to HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\8.0\Editors and find the BizTalk Orchestration Designer for us it was under Guid {679b7fd6-2104-42b2-8d87-86dd575fc269}
3) Get the package key Guid, for us this was {2f926337-2bfb-46ab-bbc4-a955ce25ff6f}
4) Go to HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\8.0\Packages\{Package Key Guid}\SkipLoading
5) Set the SkipLoading key to 0
6) Restart Visual Studio and the Orchestration Designer should show up in the "Open With" list

Does anyone know why the SkipLoading key is mysterously turned on for the Orchestration Designer?


Tuesday, April 10, 2007 #

In the past I have noticed that system testers find it difficult to test middleware applications such as those implemented using BizTalk. System testers generally don't want to read BizTalk xml messages dumped out to disk, they like to be able to query for their test results via some form of GUI. Many are adept at writing SQL to return result sets containing the test data they want to analyze.

I came up with the idea of using BAM relationships between different activities within a single view to log before and after snapshots of BizTalk messages. So when messages were transformed by maps, orchestrations or the BRE system testers could test those transforms. You can then give system testers’ access to the BAM Portal Website where they could view and query these before and after snapshots and match the actuals against the expected results to pass or fail their tests.

This solution for system testing only works for certain scenarios’ with certain types of schemas as each message logged cannot contain repeating records if it is to be logged to BAM.

So what am I on about? Take a single record schema which validates an xml message like the one below as I said before this technique won't work with messages which contain multiple records.

   <ns1:SampleTransaction TransactionID="123456" ProductName="ABC" Amount="1234.56" Quantity="24" xmlns:ns1="http://SynbogalooSamples/SampleTransaction/1.0.0.0" />

Each time a map, orchestration or business rules were applied to a message I wanted to send messages to BAM so I was basically just logging messages to BAM each time the contents of the message changed. I used BAM relationships to associate the message before it was transformed to the message after it was transformed so the tester could assess whether the transformation worked.

OK this was all easy but very time consuming using the Excel add-in to create the xlsb files for each schema so I wrote a simple xlsb file generator. Note: For this code to work with schemas that have xsd types other than DateTime, Integer, Double and String you will need to add to the switch statement in the CreateActivity method.

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;

namespace BAMXslbGenerator
{
    class Program
    {
        private const string UCName = "Name";
        private const string LCName = "name";
        private const string View = "View";
        private const string BAMDefinition = "BAMDefinition";
        private const string BAMDefinitionNamespace = "
http://schemas.microsoft.com/BizTalkServer/2004/10/BAM";
        private const string Extension = "Extension";
        private const string OWC = "OWC";
        private const string OWCNamespace = "urn:schemas-microsoft-com:office:excel";
        private const string ActivityView = "ActivityView";
        private const string ActivityRef = "ActivityRef";
        private const string Activity = "Activity";
        private const string Alias = "Alias";
        private const string CheckpointRef = "CheckpointRef";
        private const string Id = "ID";
        private const string Checkpoint = "Checkpoint";
        private const string XpathToAttribute =
            "(//*[local-name()='element'])[last()]/*[local-name()='complexType']/*[local-name()='attribute']";
        private const string DataType = "DataType";
        private const string DataLength = "DataLength";
        private const string Length = "length";
        private const string MaxLength = "maxLength";
        private const string XpathToLength = "*[local-name()='simpleType']/*[local-name()='restriction']/*[local-name()='length']/@value";
        private const string XpathToMaxLength = "*[local-name()='simpleType']/*[local-name()='restriction']/*[local-name()='maxLength']/@value";
        private const string SqlDateTime = "DATETIME";
        private const string SqlNvarchar = "NVARCHAR";
        private const string SqlInt = "INT";
        private const string SqlFloat = "FLOAT";
        private const string XsdDateTime = "xs:dateTime";
        private const string XsdString = "xs:string";
        private const string XsdInteger = "xs:int";
        private const string XsdDouble = "xs:double";

        private static StringBuilder xlsbText = null;

        static void Main(string[] args)
        {
            try
            {
                //Check for help
                if (args.Length == 0)
                {
                    ShowUsageMessage();
                }
                else if ((args[0] == "/?") || (args[0] == "/help"))
                {
                    ShowUsageMessage();
                }
                else
                {
                    //Parse out command line arguements
                    string xlsbFileNameArg = GetCommand("/x", args);
                    string viewNameArg = GetCommand("/v", args);
                    string activityNameArg = GetCommand("/a", args).Replace("[","").Replace("]","");
                    string schemaArg = GetCommand("/s", args).Replace("[", "").Replace("]", ""); ;

                    if (xlsbFileNameArg != string.Empty && viewNameArg != string.Empty
                        && activityNameArg != string.Empty && schemaArg != string.Empty)
                    {
                        string[] activityNames = activityNameArg.Split(new string[] { "," }, StringSplitOptions.None);
                        string[] schemas = schemaArg.Split(new string[] { "," }, StringSplitOptions.None);

                        GenerateXlsbXml(viewNameArg, activityNames, schemas);
                       
                        //Write out the file
                        File.Delete(xlsbFileNameArg);
                        File.AppendAllText(xlsbFileNameArg, xlsbText.ToString(), Encoding.Unicode);
                    }
                    else
                    {
                        Console.WriteLine("Incorrect arguements!");
                    }
                }
            }
            catch (System.Exception ex)
            {
                Console.Write(ex.ToString());
            }
        }

        private static string GetCommand(string commandToken, string[] args)
        {
            string commandValue = string.Empty;

            for (int i = 0; i < args.Length; i++)
            {
                if (args[i] == commandToken)
                {
                    commandValue = args[i + 1];
                    break;
                }
            }
            return commandValue;
        }

        private static void ShowUsageMessage()
        {
            Console.WriteLine("Generates an xlsb BAM definition file conaining one view and multiple schema definitions to log to BAM.");
            Console.WriteLine("Syntax: BAMXlsbGenerator");
            Console.WriteLine("Commands:");
            Console.WriteLine("\t/x \txlsb file name");
            Console.WriteLine("\t/v \tBAM View definition name");
            Console.WriteLine("\t/a[] \tActivity names enclosed in [] comma separated, there must be one activity name per schema.");
            Console.WriteLine("\t/s[] \tSchema names enclosed in [] comma separated, there must be one schema name per activity.");
            Console.WriteLine("\t/? or /help \tDisplay this usage message");
        }

        private static void GenerateXlsbXml(string viewName, string[] activityNames, string[] schemas)
        {
            //Create an writer for building the xlsb
            xlsbText = new StringBuilder();
            XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
            xmlWriterSettings.Indent = true;
            XmlWriter xlsbWriter = XmlWriter.Create(xlsbText, xmlWriterSettings);

            //Start building xml
            xlsbWriter.WriteStartDocument();
            xlsbWriter.WriteStartElement(BAMDefinition, BAMDefinitionNamespace);

            if (schemas.Length != activityNames.Length)
            {
                throw new ApplicationException("The number of activity names and schemas don't match.");
            }

            Dictionary<string, string>[] checkpointIDsForSchemas = new Dictionary<string, string>[schemas.Length];
            string[] activityIDs = new string[schemas.Length];

            //Create the activities
            for (int i = 0; i < schemas.Length; i++)
            {
                Dictionary<string, string> checkpointIDs;
                string activityID;
                CreateActivity(xlsbWriter, schemas[i], activityNames[i],
                    out checkpointIDs, out activityID);
                checkpointIDsForSchemas[i] = checkpointIDs;
                activityIDs[i] = activityID;
            }

            //Now create the view
            xlsbWriter.WriteStartElement(View);
            xlsbWriter.WriteAttributeString(UCName, viewName);
            string viewID = Id + Guid.NewGuid().ToString("N");
            xlsbWriter.WriteAttributeString(Id, viewID);

            //Create Activity Views
            for (int i = 0; i < schemas.Length; i++)
            {
                CreateActivityView(xlsbWriter, activityNames[i],
                    checkpointIDsForSchemas[i], activityIDs[i]);
            }

            xlsbWriter.WriteEndElement(); //END View

            xlsbWriter.WriteStartElement(Extension);
            xlsbWriter.WriteElementString(OWC, OWCNamespace, "");

            xlsbWriter.WriteEndElement(); //END Extension
            xlsbWriter.WriteEndElement(); //END BAMDefinition
            xlsbWriter.WriteEndDocument();
            xlsbWriter.Flush();
        }

        private static void CreateActivityView(XmlWriter xlsbWriter, string activityName,
            Dictionary<string, string> checkpointIDs, string activityID)
        {
            xlsbWriter.WriteStartElement(ActivityView);
            xlsbWriter.WriteAttributeString(UCName, View + activityName);
            xlsbWriter.WriteAttributeString(Id, Id + Guid.NewGuid().ToString("N"));
            xlsbWriter.WriteAttributeString(ActivityRef, activityID);

            //Loop through the dictionary and create the Aliases
            foreach (string key in checkpointIDs.Keys)
            {
                xlsbWriter.WriteStartElement(Alias);
                xlsbWriter.WriteAttributeString(UCName, key);
                xlsbWriter.WriteAttributeString(Id, Id + Guid.NewGuid().ToString("N"));
                xlsbWriter.WriteElementString(CheckpointRef, checkpointIDs[key]);
                xlsbWriter.WriteEndElement(); //END Alias  
            }

            xlsbWriter.WriteEndElement(); //END ActivityView 
        }

        private static void CreateActivity(XmlWriter xlsbWriter, string schema,
            string activityName, out Dictionary<string, string> checkpointIDs,
            out string activityID)
        {
            xlsbWriter.WriteStartElement(Activity);
            xlsbWriter.WriteAttributeString(UCName, activityName);
            activityID = Id + Guid.NewGuid().ToString("N");
            xlsbWriter.WriteAttributeString(Id, activityID);

            //Create a dictionary object to store the IDs in
            checkpointIDs = new Dictionary<string, string>();

            //Open the schema
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(schema);

            //The rules are

            XmlNodeList xmlNodeList = xmlDocument.SelectNodes(XpathToAttribute);

            //Loop through all the attributes and create the new xslb schema
            foreach (XmlNode xmlNode in xmlNodeList)
            {
                string checkpointID = Id + Guid.NewGuid().ToString("N");
                checkpointIDs.Add(xmlNode.Attributes[LCName].Value, checkpointID);

                //Add the data type attributes
                if (xmlNode.OuterXml.Contains(XsdDateTime))
                {
                    xlsbWriter.WriteStartElement(Checkpoint);
                    xlsbWriter.WriteAttributeString(UCName, xmlNode.Attributes[LCName].Value);
                    xlsbWriter.WriteAttributeString(Id, checkpointID);

                    xlsbWriter.WriteAttributeString(DataType, SqlDateTime);

                    xlsbWriter.WriteEndElement(); //End Checkpoint
                }
                else if (xmlNode.OuterXml.Contains(XsdInteger))
                {
                    xlsbWriter.WriteStartElement(Checkpoint);
                    xlsbWriter.WriteAttributeString(UCName, xmlNode.Attributes[LCName].Value);
                    xlsbWriter.WriteAttributeString(Id, checkpointID);

                    xlsbWriter.WriteAttributeString(DataType, SqlInt);

                    xlsbWriter.WriteEndElement(); //End Checkpoint
                }
                else if (xmlNode.OuterXml.Contains(XsdDouble))
                {
                    xlsbWriter.WriteStartElement(Checkpoint);
                    xlsbWriter.WriteAttributeString(UCName, xmlNode.Attributes[LCName].Value);
                    xlsbWriter.WriteAttributeString(Id, checkpointID);

                    xlsbWriter.WriteAttributeString(DataType, SqlFloat);

                    xlsbWriter.WriteEndElement(); //End Checkpoint
                }
                else if (xmlNode.InnerXml.Contains(XsdString))
                {
                    xlsbWriter.WriteStartElement(Checkpoint);
                    xlsbWriter.WriteAttributeString(UCName, xmlNode.Attributes[LCName].Value);
                    xlsbWriter.WriteAttributeString(Id, checkpointID);

                    xlsbWriter.WriteAttributeString(DataType, SqlNvarchar);

                    if (xmlNode.InnerXml.Contains(Length))
                    {
                        xlsbWriter.WriteAttributeString(DataLength,
                            xmlNode.SelectSingleNode(XpathToLength).InnerText);
                    }
                    else if (xmlNode.InnerXml.Contains(MaxLength))
                    {
                        xlsbWriter.WriteAttributeString(DataLength,
                            xmlNode.SelectSingleNode(XpathToMaxLength).InnerText);
                    }
                    else
                    {
                        xlsbWriter.WriteAttributeString(DataLength, "255");
                    }

                    xlsbWriter.WriteEndElement(); //End Checkpoint
                }
                else if (xmlNode.OuterXml.Contains(XsdString))
                {
                    xlsbWriter.WriteStartElement(Checkpoint);
                    xlsbWriter.WriteAttributeString(UCName, xmlNode.Attributes[LCName].Value);
                    xlsbWriter.WriteAttributeString(Id, checkpointID);

                    xlsbWriter.WriteAttributeString(DataType, SqlNvarchar);
                    xlsbWriter.WriteAttributeString(DataLength, "255");

                    xlsbWriter.WriteEndElement(); //End Checkpoint
                }
                else
                {
                    Console.Write("Unknown xsd datatype: " + xmlNode.OuterXml + " continuing to create xlsb.");
                    checkpointIDs.Remove(xmlNode.Attributes[LCName].Value);
                }
            }
            xlsbWriter.WriteEndElement(); //End Activity
        }
    }
}

How to call example: BAMXlsbGenerator /x "C:\Projects\SynboogalooSamples\Test.xlsb" /v TestView /a [TestActivityA,TestActivityB] /s [C:\Projects\SynboogalooSamples\SampleTransactionA.xsd,C:\Projects\SynboogalooSamples\SampleTransactionB.xsd]

This saved me a lot of time all I needed to do now to finish setting up BAM was deploy the xlsb BAM definition using the BM.exe tool and use the Tracking Profile Editor to associate the message payload with the BAM activity definition about 5 minutes of drag n' drop work. In the BAM Portal system testers can query transformed data and can even query the BAM tables if they want. They are able through BAM relationships to view the message contents each time it has been modified and logged to BAM.

I found this technique was a quick and simple way of empowering system testers to test BizTalk applications.

I should note another option for System Testing EAI solutions is to go with an implementation of FIT (Framework For Integration Testing)  here is a blog with more info.

Rob


Wednesday, April 04, 2007 #

84% it wasn't that bad, but it should have been easy after 3+ years working with BizTalk, lots on BAM and the BRE. I think I lost marks on the drag and drop questions and there was a tricky question on coding a BRE fact retriever. I used Saravana's exam preparation diary.

Tuesday, April 03, 2007 #

BizTalk Server 2006 R2 Beta 2 released - Thanks Mike ;)


Monday, March 26, 2007 #

A client was getting this compile error "in a sequential convoy the ports must be identical" when compiling an orchestration which had two consecutive receive ports in a sequential convoy. The answer was simple they needed to use a concurrent convoy not a sequential convoy.


Thursday, March 29, 2007 #

If you haven't already download and install the Service Factory it really reduces the time taken to build and publish your WCF services to IIS letting you concentrate on implementing business logic. Unfortunately it doesn't come with any refactoring functionality.

 


Thursday, March 22, 2007 #

I haven't posted for a while I've just finished work on a Banks SOA framework written with extensive use of WCF (which is very very extensible!). Started work implementing their Kiwisaver group investments initiative in BizTalk 2006 R2. We were one of the first out of the blocks in utilising the R2 WCF adapter (could be a bit more configurable), the WCF interceptor and AS2 adapter (interesting BAM continuations). Then after 3 years I decided to leave Synergy and go freelance for a while before moving back to the UK. On the same day I left Synergy I sold my bach and bought a new investment property so it's been busy.

It's been a truly fabulous 3 years working for Synergy International in New Zealand which has recently been re-branded as Fronde. For those of you looking for a change to kick start career development this professional organisation is continuing to grow in all the right directions, they offer great training opportunities, working and learning from very experienced people in a family oriented enviroment.

Well for the next few months I'm integrating a portfolio CRM to an investment banks core trading systems again in BizTalk and among other things using BAM for system testing which I will post on later.

Ciao

Rob


Friday, April 22, 2005 #

This is a simple explanation of how to join together two schemas with a 1:1 relationship between them in the Biztalk Mapper. I came across this problem when I had 2 legacy csv files which needed to be merged (using a unique identifier field in each file) before further processing could occur in a Biztalk Orchestration.

I will show by example. The example is a bit convoluted, but stay with me ;) different departments are ordering the same parts but are paying different prices we want to see the difference in price for the parts. There are also fields missing from each field which we want to add to the finished schema.

1) So first create 2 schemas one for each department, note the common PartID which is the unique identifier and price, but also not that one file comes with a Part name and another with a manufacturer:


2) Create the Output Schema

3) Now create an orchestration which will call the Map to join the two schemas by taking them both in and using a transform shape to map the two then it will output them

4) Set the transform properties as below create a new map set the destination to the output map

5) Which will create a map

6) Finally the biz … ok on the map join the common fields from the first schema (but not the second) with fields in the output schema now add a script functoid and set it up like this. Using an XSLT template it will search the second message for the values (simple xpath) where the PartID in the first message matches the PartID in the second message. It will then return the value of the price attribute in the second message. From this you can see how powerful using inline xslt is.

7) Add another script block to get the manufacturer field set the inline script buffer to:

 

 

9) Join up the schemas in the final map like so … THE END!

R. Addis


Wednesday, April 27, 2005 #

An instance of the Biztalk MessageContext is created and stays with each message until the message leaves Biztalk. It contains properties such as RecievePortName, RecieveFileName, MessageType i.e. all the meta data for a message.

If you want to modify this meta data you need to modify the IBaseMessageContext using either the following methods, this may be done in either a custom pipeline component or inside an orchestration:

IBaseMessageContext.Promote: Make the Message Context property a promoted property

IBaseMessageContext.Write: Make the Message Context Property a distinguished property

Where you make the call to modify the message context depends on WHEN it should be modified. If you want to use a message context property to correlate two messages you should do it inside a custom pipeline component. If you want to set the message context during processing after some decision logic do so in a Message Assignment shape in an Orchestration. We are only looking at doing it in a custom pipeline component.

An example of using this would be if you had two input files which needed to be correlated in an orchestration based on an id or date in the filename which defined a relationship between those files. Another example of a problem this would solve is found here: http://www.eggheadcafe.com/ng/microsoft.public.biztalk.server/post21008841.asp

So in both these cases we want to look at the file name of the message, extract and promote part of it so we can either use that extracted information to either correlate two or more incoming messages or base some decision logic on those properties. The way I’m going to show you how to do it is to actually overwrite the RecieveFileName property with the extracted value from it.

Notes:

              I am going to show you how we did it instead of just giving you code or a solution.

              Although I think “Biztalk Server 2004 Unleashed” tries too cover too much in one book it does have a very good explanation of Pipelines and what the different stages of a pipeline should implement.  

1)      Download Martijn Hoogendoorns’ Pipeline Component Wizard http://www.gotdotnet.com/Workspaces/Workspace.aspx?id=1d4f7d6b-7d27-4f05-a8ee-48cfcd5abf4a and install it:

a.       Unzip the source code, open the Visual Studio sln file and rebuild the PipelineComponentWizardSetup project.

b.       Right-click the PipelineComponentWizardSetup project and select “Install” to install it.

2)      In your Biztalk project add a new project and select Biztalk Server Pipeline Component Project set the following properties in the wizard.

3)     Explaining all of the Interfaces which are implemented in a pipeline component is not in the scope of this post. I will   however advise you to take a quick look and familiarise your self with the following methods which implement the PropertyBag: Load, Save, ReadPropertyBag, WritePropertyBag.

The method of the Decode Pipeline Component which does the Biz is the Execute method to which we add the following code:

public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)

{

//Make sure the message contexts property name isn't empty

       if (_PropertyName != null)

                     {

              //Get the current value of the property

              object oPropertyValue = inmsg.Context.Read(_PropertyName, _PropertyNamespace);

              if (oPropertyValue != null)

              {

                     string sPropertyValue = (string)oPropertyValue;

                     System.Text.RegularExpressions.Regex oReplaceRegularExpression =

                     new

                     System.Text.RegularExpressions.Regex(_ReplaceRegularExpression);

                                 

                     //Replace the regular expression with the value specified

              sPropertyValue =

              oReplaceRegularExpression.Replace(sPropertyValue,_Value);

                                 

                     //Either promote or distinguish the property

                     if (_PromoteOrDistinguish == "Promote")

                     {

                           inmsg.Context.Promote(_PropertyName, _PropertyNamespace,

                           sPropertyValue);

                     }

                     else if (_PromoteOrDistinguish == "Distinguish")

                     {

                            inmsg.Context.Write(_PropertyName, _PropertyNamespace,

                           sPropertyValue);

                     }

              }

                                                        

return inmsg;

}

Note I have also changed the Value property to allow you replace with an empty string so you can remove characters using a regular expression.

        public string Value

        {

            get

            {

                return _Value;

            }

            set

            {

              if (value == null)

              {

                     _Value = string.Empty;

              }

              else

              {

                     _Value = value;

              }

               

            }

        }

4)     Well that’s the development easy aye thanks to the Pipeline Component Wizard. As for testing I guess you could do this by STOP PRESS a much better way of debugging a pipeline:

              referencing the new pipeline component project in your Biztalk project

              change the output path in the pipeline components project properties dialog to C:\Program Files\Microsoft BizTalk Server 2004\Pipeline Components

              adding the compiled pipeline dll as a component by right clicking on the pipeline component toolbar and choosing add new item then selecting the Biztalk Pipeline Components Tab

              placing a breakpoint in the Execute method code

              add the component to the decode stage of a pipeline where you want to use it set the properties on the decode component to (this is just a suggestion, the regular expression tries to remove all the characters around a date which was in a filename setting the ReceivedFileName property to a date)

              deploy your Biztalk project

              set up a receive port & location

              attach to the BTSNTSvc,exe process

              drop a file in the receive location and hopefully the debug runtime will stop at your breakpoint

5)     To use the modified and promoted RecieveFileName property to correlate two messages

              create a Correlation Type and set the “Correlation Type Properties” property to FILE.ReceivedFileName

              create a Correlation Set based on this type

              initialise the correlation set property of the receive shape (for the messages which need to be correlated) to the name of the correlation set you created above

R. Addis


Monday, July 10, 2006 #

Last year at the Microsoft BPI Conference in Seattle over a few beers Scott Alan (a Microsoft integration technology specialist) shared with me his idea about using ASP.net 2.0 Web Parts to present BAM data. The idea was to give managers a more precise, flexible and easy to use interface into their business processes, they could essentially go to one dashboard and get a historical and current view of how various areas of their business unit or organisation were doing.

I’ve searched the blogosphere half a year later and I’m surprised no one has written about this it’s so simple to build.

The only gripe I have is that ASP.net 2.0 Web Parts cannot be deployed to SharePoint Services 2003 you’ll have to wait until the next version out later this year. You can however get to grips with how build Web Parts to show BAM data on an ASP.net 2.0 page now. (you can use Son of SmartPart see feedback below)

This post isn’t going to cover how to enable BAM it also isn’t about how to build Web Parts the basics of which are covered in these 3 tutorials:

WebParts1

WebParts2

WebParts3

Here is a simple BAM dashboard (ok I’m not a graphic designer). From the right hand side of the page the manager selects what data in which format they want to view and where on the page it should sit. Once the web part is on the page they can drag it to where ever they want or get rid of it and display another one.

All the Web Parts

 How to plug into BAM

I know of three ways to access BAM data the first is obvious just grab it from the Views in the BAMPrimaryImport database, the second is by accessing the cubes in SQL Server Anaylsis Services the third is by calling the Web Services which the BAM Portal uses to access BAM data (these are installed with BAM):

http://[server]/BAM/BAMQueryService/BamQueryService.asmx

 http://[server]/BAM/BAMManagementService/BamManagementService.asmx 

 

I developed 3 simple Web User Controls to display BAM Data, as a best practice I think it’s a good idea if you develop all your web parts as Web User Controls (these will be later wrapped up as Web Parts).

Web Part

Usage

Access method

Orders for Redmond