Team Foundation Server: Bug in Team Build

We found a bug in the Release Candidate version of Team Foundation Server which I shall ‘report’ here.   We accidentally found ourselves in the position of having a team build containing two Visual Studio solutions and a project that was included in both solutions.   It appears that TFS Build cannot perform builds in this situation.   When it gets to the compilation build step for the ‘shared’ project, if aborts abnormally.   The error in the Windows event log reports a SOAP fault caused by a SQL 512 error which indicates that a SQL sub-select is returning multiple rows in a situation where only one row is permissible.  The error message is:


 


“Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.”


 


Looking at the event log on the TFS server, I can see that the error occurs on line 46 of the sp_InsertProjectDetails stored procedure, and occurs when TFS Build invokes the http://<tfsserver>/Build/v1.0/BuildStore.asmx web service.   Unfortunately, stored procedures are encrypted in the TFSBuild database, so I can’t investigate this further.


 


It looks like TFS Build analyses all the solutions within a build and records each solution and project file it finds in The FileDirectory table.   The ProjectDetails table contains a ProjectFileId column containing the ID of a solution or project file, and also a ParentProjectFileId column, both of which act as foreign keys for entries in FileDirectory.   For my build, this table records the Project File Id of the ‘shared’ project against two different Parent Project File Ids, corresponding to the two solutions.   It looks like sp_InsertProjectDetails selects data from the ProjectDetails table within a sub-select, and makes an unjustified assumption that each ProjectFileId appears just once within this table.


 


The workaround was, of course, very simple.   Ensure that each project appears in just on solution per team build.   What a pity Microsoft’s test scripts for TFS Build were not written to test for this scenario.

BizTalk Server 2006 Documentation Now Available

Curious about BizTalk Server 2006 features and functionality?  A preview of the final product documentation in .chm format is available here: http://blogs.msdn.com/luke/archive/2006/02/03/524534.aspx


Check out the performance content under the topic “Planning for Sustained Performance“.  Under this topic, we provide maximum sustainable throughput numbers with and without tracking, plus tips and tricks, scaling guidence, project planning, throttling, and more!

WCF SDK Preview

Nicholas Allen, Program Manager on the Windows Communication Foundation team, has been posting some great developer material on his blog for the past few weeks. He’s now offered to post the preliminary versions of some of his SDK materials to his blog for user feedback. What a guy! I’d highly suggest taking advantage of his […]

Odds and Ends, and March Twin Cities BizTalk User Group

Well, I haven’t been posting much for the past few months.  I’ve had a lot of things going on including starting with Digineer in January.  I spent a few weeks working on business development which was a lot of fun and a great experience.  I started getting back into delivery a few weeks ago and now I’m mostly focused on that again and probably will be for quite some time.  And this means I should be back to posting on BizTalk on a more regular basis.


 


I also had the pleasure of attending QuickLearn’s BizTalk DeepDive class in Redmond last week, which I highly recommend.  The instructors, John Calloway and Jon Flanders, did a great job and I learned quite a few things.  I wish I had another week with them.


 


Finally, on March 16th, at the Twin Cities BizTalk User Group I will be presenting on ‘Orchestration Concepts: Message Construction, Direct Binding, and Configuration’.  For more information, and to register, please reference this link:  http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032292430&Culture=en-US

74-135 ‘Developing E-Business Solutions Using Microsoft BizTalk Server 2004’ now an MCTS exam?

I finally got around to taking this exam this morning.  While reviewing the exam guide (http://www.microsoft.com/learning/exams/74-135.asp) I noticed in the news section that this is now an MCTS exam… although it doesn’t include it in the list of exams on the MCTS page (http://www.microsoft.com/learning/mcp/mcts/default.asp)


[Update – the test appears on my cert transcript as an MCTS exam.]


 

Transactional pipeline components and error handling

A question came up on the Commerce Server newsgroups recently about transactional pipeline components. It boiled down to: “What is the proper way to build a transactional SQL pipeline component?”. Well, it turns out there’s really nothing special you need to do. By default, any SqlConnection you create and use in your pipeline component will automatically enlist in the DTC transaction if there is one. According to this MSDN reference on Accessing the Current Transaction, “For database connections, ADO.NET checks Transaction.Current automatically when the Connection.Open method is called, and transparently enlists the connection in that transaction (unless the Enlist keyword is set to false in the connection string).”


I’ve included the sample component I built to test this out with the Commerce Server 2007 Starter Site, but the same code should work with a Commerce Server 2002 Feature Pack 1 site, I believe.


The proper way to use transactions with the checkout process is often misunderstood. You should mark the entire checkout page as transacted:


<%@ Page Language=”C#” CodeFile=”Total.aspx.cs” Inherits=”Checkout_Total” Transaction=”RequiresNew” %>

On the checkout page you need to run all three of the main pipelines together before committing the order: basket, total, and checkout, in that order. The checkout pipeline is the only one that needs to be configured as transacted in the Web.config. This just means a transaction is required for that pipeline to execute. The other pipelines will participate in the outer page transaction if one exists (to COM+ they are registered as transactions Supported, but not required). The Basket.SaveAsOrder() method will also participate in the transaction. Thus if any failure (or warning) is reported by any pipeline component in any of the pipelines, the transaction will be rolled back and the basket will remain in the pre-checkout state.


Pipeline components can report their completion status in a couple of different ways. If the component fails for some fatal/unrecoverable reason such as SQL server being unavailable, then the component can throw an exception. In COM terms, that means setting the HRESULT to the appropriate failure code and setting the IErrorInfo on the thread. For .NET components, they can simply throw an exception and let the CLR’s .NET interop facilities translate that into an HRESULT. Another way a component can denote failure (not recommended) is by returning a value greater or equal to Error (3). In this case the OrderGroup.RunPipeline() method will throw a PipelineExecutionException.


If the component excecutes successfully but needs to report a business validation error, it should return an error level of Warning (2). This indicates the component executed successfully but reported warnings (use Success (1) to indicate completion with no errors or warnings; you shouldn’t use an error level of zero as that’s not defined). A well-behaved component that reports such a warning should also add a string to either the _Basket_Errors or _Purchase_Errors lists, depending on which pipeline the component is associated with (_Basket_Errors for the basket and total pipelines and _Purchase_Errors for the checkout pipeline is the general guideline – the distinction is mostly legacy – you should check for and display messages from both lists as a rule).


A transactional pipeline will not vote to commit the transaction if the error level returned by a component is Warning (2) or Error (3) (or higher). You can find out the error level by checking the return value of OrderGroup.RunPipeline (a PipelineExecutionResult enum value). If it is Warning (2), the site code should be prepared to display any messages from the _Basket_Errors and _Purchase_Errors lists. These messages are usually retrieved by the pipeline component from the COM MessageManager object that is configured for the site (MessageManager is a legacy carryover from before the days of .NET ResourceManagers). MessageManager will return the localized display message corresponding to well-defined error code strings.


The below code sample is what I came up with for demonstrating and playing with this. To build this pipeline component,


  • Create a C# class library project in VS.NET 2005
  • Add references to Microsoft.CommerceServer.Interop.dll, Microsoft.CommerceServer.Shared.dll, and Microsoft.CommerceServer.Runtime.dll
  • Configure the project to register components with COM so that a .tlb will be generated
  • Regasm the assembly (with the /codebase option unless you are deploying it to the GAC)
  • Use the pipeline registration tool in the Commerce Server SDK (pipereg.exe) to register the component as a pipeline component
After all that, you should be able to use the pipeline editor to add the sample component to the checkout.pcf pipeline. Be sure that you create the table noted in the comments of the sample at line 24 in your Transactions database.


After the component has been verified to execute correctly in your checkout scenario, to test out the rollback, the easiest thing to do is add a Scriptor component to the pipeline configured to execute after the sample component. Edit the scriptor (right click in pipeline editor and select “properties”, then click the “Edit Script” button) and modify it to return error level Warn (2) or Error (3) instead of the default value of Success (1). Note that if you get back error level Warn (2) from a transacted pipeline running on a page that is set to require transactions and ignore the return value and try to run OrderGroup.SaveAsOrder anyway, then .NET will complain loudly (by throwing an exception) because you’re trying to perform SQL operations within a DTC transaction that’s already been rolled back by the pipeline infrastructure. It looks like our CS2006 Starter Site currently has this bug – moral of the story – check that return value from the pipeline!


One more thing about pipeline error levels that is little known (not sure how useful it is, but that’s a different matter) is that in the pipeline editor you can configure the “error level tolerance” of each stage in the pipeline. This can be used to skip executing certain components (entire stages, really) when the error level is greater than the configured threshold. So for example if the error threshold for the Accept stage of the checkout pipeline is one (it is, trust me), then components in that stage will not execute if any component that came before returned an error level of two or greater. Also note that the final error level returned from pipeline execution is the greatest of the error level return values from all of the components executed within the pipeline.


The final figure below the code sample is the dump output showing all the keys and values in the entire OrderForm and PipelineContext dictionaries when my component was executed in the checkout pipeline of the CS2007 starter site (current builds). The technique I used to generate that HTML is just the few lines of code starting at line 59. The DumpUtils class in the Microsoft.CommerceServer.Runtime.Diagnostics namespace is very useful when it comes to inspecting Commerce Server object hierarchies that include the COM types such as Dictionary, SimpleList, and ContentList. DumpUtils is legacy code from CS2002 (and too tightly tied to System.Web.UI), so maybe one of these days I’ll find time to update that to emit XML that can be styled instead (that would be more useful, eh?).



    1 using System;


    2 using System.Diagnostics;


    3 using System.Data;


    4 using System.Data.SqlClient;


    5 using System.Data.OleDb;


    6 using System.Collections.Generic;


    7 using System.Text;


    8 using System.IO;


    9 using System.Web.UI;


   10 


   11 using System.Runtime.InteropServices;


   12 using Microsoft.CommerceServer.Runtime;


   13 using Microsoft.CommerceServer.Runtime.Configuration;


   14 using Microsoft.CommerceServer.Runtime.Diagnostics;


   15 using Microsoft.CommerceServer.Interop;


   16 using Microsoft.CommerceServer.Interop.Orders;


   17 


   18 namespace TxSqlTester


   19 {


   20     // ===========================================================


   21     // Create this table in the Commerce Server Transactions databse


   22     // before running the sample


   23     //   


   24     //CREATE TABLE [dbo].[UserOrderInfo] (


   25     //    [UserId] [nvarchar] (50) NOT NULL ,


   26     //    [NumLineItems] [int] NOT NULL ,


   27     //    [BasketOrderGroupId] [nvarchar] (50) NOT NULL ,


   28     //    [DateTimeStamp] [datetime] NULL


   29     //)


   30     //GO


   31     //


   32     // By adding this component to the Checkout.pcf pipeline,


   33     // an entry will be written to the UserOrderInfo


   34     // table each time a checkout occurs.  If another component


   35     // down the line returns errorlevel >= 2, then the transaction


   36     // will be rolled back.


   37     // ===========================================================


   38 


   39     // A pipeline component that writes to SQL server


   40     // Note that there is no special code required to enlist in the


   41     // DTC transaction owned by the pipeline


   42     [ComVisible(true)]


   43     [GuidAttribute(“1A3CD295-A758-4e83-9301-A4BBD41D8F75”)]


   44     public class TxSqlTester : IPipelineComponent


   45     {


   46         #region IPipelineComponent Members


   47         public int Execute(object pdispOrder, object pdispContext, int lFlags)


   48         {


   49             // If any other component in the transacted pipeline returns ErrorLevel >= 2 (Warn),


   50             // then the Tx will roll back along with any SQL writes performed here.


   51 


   52             IDictionary context = (IDictionary)pdispContext;


   53             IDictionary orderForm = (IDictionary)pdispOrder;


   54 


   55             // retrieve and sanitize the Transactions connection string


   56             string txConnectionString = null;


   57             SqlUtil.CleanSqlClientConnectionString(this.GetTxConnectionString(context), out txConnectionString);


   58 


   59             //StringWriter textWriter = new StringWriter();


   60             //System.Web.UI.HtmlTextWriter output = new System.Web.UI.HtmlTextWriter(textWriter);


   61             //DumpUtils.DumpDictionary(orderForm, output, “OrderForm”);


   62             //DumpUtils.DumpDictionary(context, output, “Context”);


   63             //string dumpDictionariesAsHtml = textWriter.ToString();


   64 


   65             // retrieve the values we will be writing to the SQL table from the Order Form


   66             string userid = orderForm[“user_id”].ToString();


   67             string basketOrderGroupId = orderForm[“BasketOrderGroupId”].ToString();


   68             int numLineItems = ((ISimpleList)orderForm[“items”]).Count;


   69 


   70             // perform the SQL write operation


   71             UserOrderUpdateSql updater = new UserOrderUpdateSql(txConnectionString);


   72             updater.WriteUserOrderRecord(userid, basketOrderGroupId, numLineItems);


   73 


   74             return 1;    // (1=Success, 2=Warn, 3=Fail)


   75         }


   76 


   77         // Legacy IPipelineComponent method – no need to do anything


   78         public void EnableDesign(int fEnable)


   79         {           


   80         }


   81         #endregion // IPipelineComponent


   82 


   83         private string GetTxConnectionString(IDictionary context)


   84         {


   85             CommerceResourceCollection resources = context[“CommerceResources”] as CommerceResourceCollection;


   86             if (resources != null)


   87                 return resources[“Transactions”][“connstr_db_transactions”].ToString();


   88             else


   89                 throw new ApplicationException(“Unable to retrieve Commerce Resources”);


   90         }


   91     }


   92 


   93     //    This class inserts a row into the UserOrderInfo table.


   94     public class UserOrderUpdateSql


   95     {


   96         private string connstr;


   97 


   98         public UserOrderUpdateSql(string connstr)


   99         {


  100             this.connstr = connstr;


  101         }


  102 


  103         public void WriteUserOrderRecord(string userId, string basketOrderGroupId, int numLineItems)


  104         {


  105             SqlConnection conn = null;


  106             const string tsql =


  107                 “insert into [UserOrderInfo] ([UserId], [BasketOrderGroupId], [NumLineItems]) values (@userid, @basketid, @numlineitems)”;


  108             using (conn = new SqlConnection(connstr))


  109             {


  110                 conn.Open();


  111                 SqlCommand cmd = new SqlCommand(tsql, conn);


  112                 cmd.Parameters.Add(new SqlParameter(“@userid”, userId));


  113                 cmd.Parameters.Add(new SqlParameter(“@basketid”, basketOrderGroupId));


  114                 cmd.Parameters.Add(new SqlParameter(“@numlineitems”, numLineItems));


  115                 cmd.ExecuteNonQuery();


  116             }


  117         }


  118     }


  119 


  120     internal static class SqlUtil


  121     {


  122         // removes the “Provider” keyword present in Commerce Server connection strings so that


  123         // it will work with the SQLClient


  124         public static bool CleanSqlClientConnectionString(string connectionString, out string cleaned)


  125         {


  126             bool successStatus;


  127             cleaned = null;


  128             try


  129             {


  130                 OleDbConnectionStringBuilder builder = new OleDbConnectionStringBuilder(connectionString);


  131                 builder.Remove(“Provider”);


  132                 cleaned = builder.ConnectionString;


  133                 successStatus = true;


  134             }


  135             catch (ArgumentException)


  136             {


  137                 successStatus = false;


  138             }


  139             return successStatus;


  140         }


  141     }


  142 }



Dumping Dictionary ‘OrderForm’
_cy_oadjust_subtotal=<System.Decimal> 200
_event=<System.String> “SOLD”
_winners=<Commerce.SimpleList>
      Dumping SimpleList ‘_winners’
      <empty>
user_id=<System.String> “{575d3603-daac-42ad-b85a-dcc615e44ce8}”
promo_user_identity=<System.String> “”
shipments=<Commerce.SimpleList>
      Dumping SimpleList ‘shipments’
      <Commerce.Dictionary>
            Dumping Dictionary ‘list item 1’
            shipment_id=<System.String> “{f412aa14-6b23-47d8-a8df-96ae753ea4fe}”
            ItemIndexes=<Commerce.SimpleList>
                  Dumping SimpleList ‘ItemIndexes’
                  <System.Int32> 0
            shipping_method_name=<System.String> “Second-Day Air”
            shipping_address_id=<System.String> “24d35f86-ff97-475b-82a4-de9e29068b52”
            _shipping_discounts_applied=<Commerce.SimpleList>
                  Dumping SimpleList ‘_shipping_discounts_applied’
                  <empty>
            shipping_method_id=<System.String> “{b75f90be-49bc-47b9-b268-d5996ad3baf8}”
            _cy_shipping_total=<System.Decimal> 10
            _cy_shipping_discounts_subtotal=<System.Decimal> 0.0000
            shipment_tracking_number=<System.String> “”
            shipment_status=<System.String> “”
payments=<Commerce.SimpleList>
      Dumping SimpleList ‘payments’
      <Commerce.Dictionary>
            Dumping Dictionary ‘list item 1’
            cc_identifier=<System.String> “”
            cy_amount=<System.Decimal> 210
            PaymentProfile=<System.String> “cf634e36-9385-40d7-bfe7-6eddaff0e9b4”
            payment_id=<System.String> “{6d639441-2f9f-4417-8d9d-5d386e446bca}”
            billing_address_id=<System.String> “96ab2cc7-5587-49b6-967d-ab309b264942”
            payment_status=<System.String> “”
            authorization_code=<System.String> “”
            _cc_expyear=<System.Int32> 2009
            _cc_expmonth=<System.Int32> 1
            payment_method_name=<System.String> “Visa”
            customer_name_on_payment=<System.String> “Davied Messner”
            derived_class_name=<System.String> “CreditCardPayment”
            _cc_number=<System.String> “411111111111”
            cc_type=<System.String> “f2e8f93d-fdc2-4dfd-8239-02f6f187359a”
            validation_code=<System.String> “”
            payment_method_id=<System.String> “{f2e8f93d-fdc2-4dfd-8239-02f6f187359a}”
_Verify_With=<Commerce.Dictionary>
      Dumping Dictionary ‘_Verify_With’
      <empty>
_Purchase_Errors=<Commerce.SimpleList>
      Dumping SimpleList ‘_Purchase_Errors’
      <empty>
promo_codes=<Commerce.SimpleList>
      Dumping SimpleList ‘promo_codes’
      <empty>
_Basket_Errors=<Commerce.SimpleList>
      Dumping SimpleList ‘_Basket_Errors’
      <empty>
billing_address_id=<System.String> “96ab2cc7-5587-49b6-967d-ab309b264942”
order_id=<System.String> “A4NLAXB8VQLN9MFPBN8UJ2RX04”
orderform_id=<System.String> “{3618dbda-25cc-42cb-8784-95e5c98c9a45}”
_cy_tax_included=<System.Decimal> 0.0000
orderform_status=<System.String> “”
Addresses=<Commerce.Dictionary>
      Dumping Dictionary ‘Addresses’
      24d35f86-ff97-475b-82a4-de9e29068b52=<Commerce.Dictionary>
            Dumping Dictionary ’24d35f86-ff97-475b-82a4-de9e29068b52′
            last_name=<System.String> “Messner”
            order_group_id=<System.String> “{90551d41-c547-4c27-806d-be81d70fb5b7}”
            address_line1=<System.String> “6602 149th”
            address_id=<System.String> “24d35f86-ff97-475b-82a4-de9e29068b52”
            state=<System.String> “WA”
            region_name=<System.String> “”
            address_line2=<System.String> “”
            country_code=<System.String> “”
            email=<System.String> “”
            first_name=<System.String> “David”
            name=<System.String> “6602 149th”
            country_name=<System.String> “”
            evening_phone_number=<System.String> “”
            day_time_phone_number=<System.String> “”
            postal_code=<System.String> “98052”
            city=<System.String> “Redmond”
promo_code_info=<Commerce.SimpleList>
      Dumping SimpleList ‘promo_code_info’
      <empty>
items=<Commerce.SimpleList>
      Dumping SimpleList ‘items’
      <Commerce.Dictionary>
            Dumping Dictionary ‘list item 1’
            _product_BaseCatalogName=<System.String> “Adventure Works Catalog”
            _product_#Inv_Origvariantid#=<System.String> “3”
            _product_BackorderedQuantity=<System.Decimal> 0.0000
            _product_ProductColor=<System.String> “Blue”
            cy_placed_price=<System.Decimal> 200
            _product_categories=<Array>
                  Dumping Array ‘_product_categories’
                  <System.String> “SleepingBags”
            _product_InventoryCondition=<System.Int32> 3
            _cy_itemlevel_discounts_subtotal=<System.Decimal> 0.0000
            product_catalog=<System.String> “Adventure Works Catalog”
            _product_Image_filename=<System.String> “./images/sleepingbags03.gif”
            shipping_method_name=<System.String> “Second-Day Air”
            _product_#Catalog_Lang_Oid=<System.Int32> 96
            _product_#Inv_ProductId#=<System.String> “AW200-12”
            _cy_oadjust_discount=<System.Decimal> 0.0000
            _product_IntroductionDate=<System.DateTime> 3/3/1996 4:00:00 PM
            _product_ProductID=<System.String> “AW200-12”
            _product_LastModified=<System.DateTime> 9/28/2000 3:19:37 PM
            _product_ProductCode=<System.String> “AW200-12”
            shipping_address_id=<System.String> “24d35f86-ff97-475b-82a4-de9e29068b52”
            _product_OnSale=<System.Int32> 0
            _product_SkuTimestamp=<Array>
                  Dumping Array ‘_product_SkuTimestamp’
                  <empty>
            _product_#Inv_BaseCatalogName#=<System.String> “Adventure Works Catalog”
            _product_#Inv_variantid#=<System.String> “3”
            _product_OrigProductID=<System.String> “AW200-12”
            _cy_iadjust_currentprice=<System.Decimal> 200
            _cy_oadjust_adjustedprice=<System.Decimal> 200
            _inventory_allow_backorder_and_preorder=<System.Boolean> True
            _product_TimeStamp=<Array>
                  Dumping Array ‘_product_TimeStamp’
                  <System.Byte> 0
                  <System.Byte> 0
                  <System.Byte> 0
                  <System.Byte> 0
                  <System.Byte> 0
                  <System.Byte> 0
                  <System.Byte> 13
                  <System.Byte> 237
            _cy_iadjust_regularprice=<System.Decimal> 200
            _product_Description=<System.String> “Generously cut sleeping bag, goose down with polyster taffeta, cotton storage sack included.”
            shipping_method_id=<System.String> “{b75f90be-49bc-47b9-b268-d5996ad3baf8}”
            _product_Oid=<System.Int32> 96
            _product_InventoryCondition1=<System.Int32> 3
            product_variant_id=<System.String> “3”
            _product_ParentOID=<System.Int32> 95
            _product_i_ClassType=<System.Int32> 2
            _n_unadjusted=<System.Int32> 1
            _orderlevel_discounts_applied=<Commerce.SimpleList>
                  Dumping SimpleList ‘_orderlevel_discounts_applied’
                  <empty>
            _product_#Catalog_row_num=<System.Int32> 1
            _product_#Inv_OrigProductId#=<System.String> “AW200-12”
            _product_#Catalog_Lang_Timestamp=<Array>
                  Dumping Array ‘_product_#Catalog_Lang_Timestamp’
                  <System.Byte> 0
                  <System.Byte> 0
                  <System.Byte> 0
                  <System.Byte> 0
                  <System.Byte> 0
                  <System.Byte> 0
                  <System.Byte> 13
                  <System.Byte> 239
            _product_cy_list_price=<System.Decimal> 200
            _product_ExportReady=<System.Boolean> True
            _product_CatalogName=<System.String> “Adventure Works Catalog”
            _inventory_condition=<System.Int32> 0
            item_status=<System.String> “”
            _product_Image_width=<System.Int32> 120
            _product_OriginalPrice=<System.Decimal> 200
            index=<System.String> “{4246b16b-fdd6-4f8d-b6b3-e9741c3fa77b}”
            _inventory_back_order_for_request=<System.Decimal> 0.0000
            _product_DisplayName=<System.String> “Big Sur”
            _product_VariantCode=<System.Int32> 3
            _product_VariantID=<System.String> “3”
            _product_PreorderedQuantity=<System.Decimal> 0.0000
            _product_DefinitionName=<System.String> “SleepingBag”
            _product_Image_height=<System.Int32> 120
            _itemlevel_discounts_applied=<Commerce.SimpleList>
                  Dumping SimpleList ‘_itemlevel_discounts_applied’
                  <empty>
            _product_UseCategoryPricing=<System.Boolean> False
            _cy_orderlevel_discounts_subtotal=<System.Decimal> 0.0000
            product_id=<System.String> “AW200-12”
            _inventory_in_stock_for_request=<System.Decimal> 0.0000
            _product_Name=<System.String> “Big Sur”
            _product_OrigVariantID=<System.String> “3”
            quantity=<System.Int32> 1
            _inventory_pre_order_for_request=<System.Decimal> 0.0000
            _product_#TmpCatalogoid#=<System.Int32> 96
_cy_tax_total=<System.Decimal> 0.0000
_cy_shipping_total=<System.Decimal> 10
_discounts=<IDataContainer>
      Dumping DataContainer ‘_discounts’
      <empty>
_content=<IDataContainer>
      Dumping DataContainer ‘_content’
      <empty>
_cy_shipping_discounts_total=<System.Decimal> 0.0000
BasketOrderGroupId=<System.String> “{90551d41-c547-4c27-806d-be81d70fb5b7}”
_cy_total_total=<System.Decimal> 210
_cy_handling_total=<System.Decimal> 0.0000
_performance=<Commerce.Dictionary>
      Dumping Dictionary ‘_performance’
      <empty>


Dumping Dictionary ‘Context’
Language=<System.String> “en-US”
MessageManager=<Microsoft.CommerceServer.Interop.MessageManagerClass> Microsoft.CommerceServer.Interop.MessageManagerClass
CacheManager=<Microsoft.CommerceServer.Interop.Caching.CacheManagerClass> Microsoft.CommerceServer.Interop.Caching.CacheManagerClass
CatalogContext=<Microsoft.CommerceServer.Catalog.CatalogContext> Microsoft.CommerceServer.Catalog.CatalogContext
pipelines=<ICollection>
      Dumping Collection ‘pipelines’
      <Microsoft.CommerceServer.Runtime.Pipelines.OrderPipeline> basket
      <Microsoft.CommerceServer.Runtime.Pipelines.OrderPipeline> checkout
      <Microsoft.CommerceServer.Runtime.Pipelines.OrderPipeline> product
      <Microsoft.CommerceServer.Runtime.Pipelines.OrderPipeline> total
      <Microsoft.CommerceServer.Runtime.Pipelines.ContentSelectionPipeline> advertising
      <Microsoft.CommerceServer.Runtime.Pipelines.ContentSelectionPipeline> discounts
      <Microsoft.CommerceServer.Runtime.Pipelines.ContentSelectionPipeline> recordevent
      <Microsoft.CommerceServer.Runtime.Pipelines.OrderPipeline> creditcard
ProfileService=<Microsoft.CommerceServer.Interop.Profiles.ProfileServiceClass> Microsoft.CommerceServer.Interop.Profiles.ProfileServiceClass
CommerceResources=<ICollection>
      Dumping Collection ‘CommerceResources’
      <Microsoft.CommerceServer.Runtime.Configuration.CommerceResource> Microsoft.CommerceServer.Runtime.Configuration.CommerceResource
      <Microsoft.CommerceServer.Runtime.Configuration.CommerceResource> Microsoft.CommerceServer.Runtime.Configuration.CommerceResource
      <Microsoft.CommerceServer.Runtime.Configuration.CommerceResource> Microsoft.CommerceServer.Runtime.Configuration.CommerceResource
      <Microsoft.CommerceServer.Runtime.Configuration.CommerceResource> Microsoft.CommerceServer.Runtime.Configuration.CommerceResource
      <Microsoft.CommerceServer.Runtime.Configuration.CommerceResource> Microsoft.CommerceServer.Runtime.Configuration.CommerceResource
      <Microsoft.CommerceServer.Runtime.Configuration.CommerceResource> Microsoft.CommerceServer.Runtime.Configuration.CommerceResource
      <Microsoft.CommerceServer.Runtime.Configuration.CommerceResource> Microsoft.CommerceServer.Runtime.Configuration.CommerceResource
      <Microsoft.CommerceServer.Runtime.Configuration.CommerceResource> Microsoft.CommerceServer.Runtime.Configuration.CommerceResource
CacheName=<System.String> “Discounts”

BizTalk 2006 Deep Dive Class

Last week I was in Redmond for QuickLearn’s BizTalk Server 2006 Deep Dive.  It was great to get a dedicated week of time to look at BizTalk 2006.  While the core of the product remains the same, it’s great to see the new features.  I think everyone will be pleased with the new product!  It’s coming soon…and hopefully I’ll be able to find some time to get out a few blog entries!  One quick note, if you haven’t looked at the SDK that comes with any of the Beta’s for BizTalk 2006, please do so.  Along with the existing SDK, Microsoft has also provided several scenarios that are full applications…not just simple examples!  This is a great resource for developing Enterprise Applications.


Jon Flanders is now with QuickLearn and taught part of the BizTalk class.  I would recommend every BizTalk developer bookmark his blog site:  Mastering BizTalk Server. 

The sound of silence

OK, David’s been a really lame blog poster (as in more than 6 months not posting!!??). I guess I could use being so busy delivering quality and features in Commerce Server 2006 as an excuse. But I won’t do that. Instead I will say that I’ve been accumulating a list of CS2006 topics and code samples to blog about.


While I’m posting, I want to point out that we have a new team member blogging about the great stuff coming in Commerce Server 2006. Alan Faulkner is a tester on the team who works on the CS2006 BizTalk adapters and is now taking on much of the Data Warehouse and Reporting test work. This guy’s really become an expert on the systems, so check him out. Plus he’s an east-coast transplant like me :-).


As we approach the dreaded “end game” of Commerce Server 2006, I’ve been reflecting on the release.  Serving as a development manager is a new role from me.  I’ve been with the Commerce Server team for quite a while – since Site Server Commerce Edition was in development, in fact.  And what’s really refreshing is the increased focus on quality and excellence.  I’m also incredibly lucky to work with an extraordinarily dedicated and talented team.  This is truly the best Commerce Server team ever at Microsoft.

I hope that you’ll agree when you use the product. Our early feedback from the beta release of CS2006 has been resoundingly positive around this. We still have a little ways to go to put on all the finishing touches, fix the final wave of bugs, complete the documentation (it’s rather lacking in the Beta release – we’re working on it) and ultimately meet all of the release criteria.  But I think you’ll agree that it’s already a big step up in terms of quality and consistency.

Let me know what topics you’d like to see more technical details around. Here are some of the blog ideas I’ve accumulated. Leave me feedback if you’d find particular value in any of these or have other areas you’d like to learn more about. Since I was formerly the developer for the discounting components in Commerce Server, many of these are marketing or discount related. I prefer to write about technologies and scenarios in CS2006 but if you have pressing issues with CS2002 I’m happy to address those as well.



  • Qualifying discounts on custom properties of products that don’t come from the catalog system. This was a customer scenario where the requirement was to apply discounts to items that are recurring purchases. That can easily be achieved by adding a custom property to the line item (e.g. using the indexer) and then extending the Web service method that retrieves the “product” definitions so that the CS2006 Marketing Manager application (DiscountManager in CS2002 Feature Pack 1) will allow business users to include these properties in their discount expressions.
  • How to implement promotion codes in the CS2002 Starter Site with Feature Pack 1 (this will be “out of the box” in the CS2006 starter site).
  • About the new feature in CS2006 that allows advertisements and discounts to be targeted using Profiles other than UserObject and TargetingContext (a rather annoying limitation of the CS2002 targeting system).
  • How to implement pipeline component property pages in .NET Winforms
  • Expiring anonymous data (baskets, profiles, campaigns, etc)
  • About COM Interop in Commerce Server
  • Using codegen to build a strongly typed “Profile Object”
  • Displaying the discounted price of a product the product listings page in a site. This turns out to be really hard to do in Commerce Server 2002. We’re making it much better in CS2006 but there are some limitations.
  • Approaches to implementing bundling in Commerce Server 2006
  • How do set up a complex shipping discount scenario: If the order exceeds $250 and a certain promotion code is entered, give free shipping for “standard” shipping method only.
  • CS2006 and state/session management (a bit broad, much we could address around this)
  • How to change the precedence of how OrderDiscount awards discounts to line items (on a per line-item basis instead of the global setting that’s already available).