davidme's .NET-Commerce WebLog

Commerce Server Blog

  • Tech·Ed Chalk Talk - Commerce Server 2007 Architecture Deep Dive

    Are you going to be in Orlando for Microsoft Tech·Ed 2007?  I'll be there for part of the week and on Wednesday will present a chalk talk on Commerce Server 2007 architecture.

    WEB04-TLC - Microsoft Commerce Server 2007 Architectural Deep Dive

    Date: Wednesday 6/6/2007 10:15-11:30

    Track(s): Web Development and Infrastructure

    Level: 300

    Speaker(s): David Messner

    Abstract: This talk provides an overview of the inner-workings of Commerce Server 2007 and how the various components fit together. It includes details of the overall architecture with deep-dives on Catalog/Inventory, Profiles, Marketing, Orders, Data Warehouse, Adapters, and Staging services.

     

    Please post your comments with any requests on what you'd like to see covered or demo'd.

    Hope to see you there!

  • Moving to the Commerce Team Blog

    I've just posted to the Commerce team blog on how to use Fiddler to capture SOAP packets that are sent between CS2007 business user applications and Web services - a very handy troubleshooting technique.

    http://blogs.msdn.com/commerce/archive/2006/12/03/using-fiddler-to-capture-soap-messages-between-the-cs2007-web-services-and-clients.aspx

    I've got another blog post in the works on DateTime handling in the various Commerce Server subsystems and just need to collect a little more information on Data Warehouse DateTime handling before I post that.

    I likely won't be posting to this blog very frequently, if at all, so you can simply check the Commerce Team Blog for all the latest from me and the rest of the fine folks on the Commerce team.

    ciao,
    -David

  • Commerce Server Forums on MSDN

    The Commerce Server product team will no longer be monitoring the Commerce Server newsgroups.  Instead, we have nifty new forums set up on MSDN for both Commerce Server 2007 and earlier versions of the product.  I think you'll agree that this provides a significantly better experience for all of those concerned.  Searchability is much better, for example, you can rate posts, and we can maintain a static FAQ there as the need arises.

    Here's the link: http://forums.microsoft.com/MSDN/default.aspx?ForumGroupID=294&SiteID=1

    See you on the forums!

     

  • RSS Feed Sample for Commerce Server 2007

    We've posted a new sample to the Commerce Server Workspace on gotdotnet that shows how you can publish an RSS feed on your site that contains product information from your Commerce Server 2007 catalogs. This work is the result of a really great intern project from this summer. The project includes:

    • An RSS Subscription page where users can configure their feed
    • Classes that encapsulate the querying of catalog information and the generation of the RSS 2.0 XML
    • A PuP package containing the Commerce RSS resource (also serves as a good example of a custom resource)
    • A README file documenting the installation steps and the classes included in the project

     

    The RSS sample works together with the Commerce Server 2007 Starter Site CTP release currently. The subscription page lets a user manage their feed. The user can configure the feed to show the most recent items that have been added to the catalog. Users can also use the Subscription page to search the catalog and add items to their feed to be included in one of three conditions:

    • always include
    • include when on sale (discount applies)
    • include when in stock

     

    The instructions cover adding a button on the product page so a user can add the product to their custom feed. For example users might track the item for price updates or for inventory condition changes. It's not hard to imagine more advanced scenarios that utilize custom schema extensions in the RSS XML that allow rich cross-site sharing of catalog data.

    The usual disclaimers apply (see the license on the gotdotnet site).

  • Commerce Server 2007 technical training screencasts

    With the offical launch of Commerce Server 2007 just around the corner, the excitement around these halls is really growing.  Interest in Commerce Server is definitely at an all time high and we have a record number of customers working on new site development.  The engineering team has been working on producing a set of technical training screencasts produced by developers for developers and covering the various subsystems of the product.  We'll have a few of these available at the time of the launch and several more coming out in the upcoming weeks.  You might notice that we're not professional presenters, but I hope that you'll realize a lot of value from them nonetheless.

    Here's the link (added 8/1/06): http://www.microsoft.com/technet/prodtechnol/comm/2007/webcasts.mspx

    On the cool technology front, I'm really excited about the Concurrency and Coordination Runtime (CCR) that is at the heart of the new MS Robitics Studio.  I really buy into the design approach and I think the tools in the CCR are applicable to just about any application domain, certainly not just robotics.  I'm currently reading David West's book on Object Thinking (highly recommended) and I find the thoughts there congruous with the messaging philosophy underlying the CCR.  And with many-core CPU's being the next big thing, we need approaches like this to fully realize the value of the concurrency they can provide.  I can't wait to try this stuff out.

    Personally I just got back from Las Vegas where I attended my brother's wedding.  He was married at the Wynn Hotel and Resort.  We upgraded to a panoramic room which basically means you're up higher than anything else along the strip and have a great view.  But it certainly is a pricey place - definitely targeted toward the high rollers (which I certainly am not - thank goodness for the $5 single deck blackjack at TI across the street).  I'm amazed at the amount of construction currently underway down there.  The Venetian next door is being expanded and I hear that it will be the largest hotel in the world when completed.  Then the Trump International Hotel and Tower is going up across the street, which will the tallest when completed.  I hear the Luxor is coming down - they say it's a waste of space.  Too bad, it's a cool hotel.  Perhaps if the Mix '07 Web conference is at the Venetian again I'll make it down to Vegas again next year.  Maybe I'll see you there.

  • 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?).

    using System;

    using System.Diagnostics;

    using System.Data;

    using System.Data.SqlClient;

    using System.Data.OleDb;

    using System.Collections.Generic;

    using System.Text;

    using System.IO;

    using System.Web.UI;

     

    using System.Runtime.InteropServices;

    using Microsoft.CommerceServer.Runtime;

    using Microsoft.CommerceServer.Runtime.Configuration;

    using Microsoft.CommerceServer.Runtime.Diagnostics;

    using Microsoft.CommerceServer.Interop;

    using Microsoft.CommerceServer.Interop.Orders;

     

    namespace TxSqlTester

    {

        // ===========================================================

        // Create this table in the Commerce Server Transactions databse

        // before running the sample

        //   

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

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

        //    [NumLineItems] [int] NOT NULL ,

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

        //    [DateTimeStamp] [datetime] NULL

        //)

        //GO

        //

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

        // an entry will be written to the UserOrderInfo

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

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

        // will be rolled back.

        // ===========================================================

     

        // A pipeline component that writes to SQL server

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

        // DTC transaction owned by the pipeline

        [ComVisible(true)]

        [GuidAttribute("1A3CD295-A758-4e83-9301-A4BBD41D8F75")]

        public class TxSqlTester : IPipelineComponent

        {

            #region IPipelineComponent Members

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

            {

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

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

     

                IDictionary context = (IDictionary)pdispContext;

                IDictionary orderForm = (IDictionary)pdispOrder;

     

                // retrieve and sanitize the Transactions connection string

                string txConnectionString = null;

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

     

                //StringWriter textWriter = new StringWriter();

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

                //DumpUtils.DumpDictionary(orderForm, output, "OrderForm");

                //DumpUtils.DumpDictionary(context, output, "Context");

                //string dumpDictionariesAsHtml = textWriter.ToString();

     

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

                string userid = orderForm["user_id"].ToString();

                string basketOrderGroupId = orderForm["BasketOrderGroupId"].ToString();

                int numLineItems = ((ISimpleList)orderForm["items"]).Count;

     

                // perform the SQL write operation

                UserOrderUpdateSql updater = new UserOrderUpdateSql(txConnectionString);

                updater.WriteUserOrderRecord(userid, basketOrderGroupId, numLineItems);

     

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

            }

     

            // Legacy IPipelineComponent method - no need to do anything

            public void EnableDesign(int fEnable)

            {           

            }

            #endregion // IPipelineComponent

     

            private string GetTxConnectionString(IDictionary context)

            {

                CommerceResourceCollection resources = context["CommerceResources"] as CommerceResourceCollection;

                if (resources != null)

                    return resources["Transactions"]["connstr_db_transactions"].ToString();

                else

                    throw new ApplicationException("Unable to retrieve Commerce Resources");

            }

        }

     

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

        public class UserOrderUpdateSql

        {

            private string connstr;

     

            public UserOrderUpdateSql(string connstr)

            {

                this.connstr = connstr;

            }

     

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

            {

                SqlConnection conn = null;

                const string tsql =

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

                using (conn = new SqlConnection(connstr))

                {

                    conn.Open();

                    SqlCommand cmd = new SqlCommand(tsql, conn);

                    cmd.Parameters.Add(new SqlParameter("@userid", userId));

                    cmd.Parameters.Add(new SqlParameter("@basketid", basketOrderGroupId));

                    cmd.Parameters.Add(new SqlParameter("@numlineitems", numLineItems));

                    cmd.ExecuteNonQuery();

                }

            }

        }

     

        internal static class SqlUtil

        {

            // removes the "Provider" keyword present in Commerce Server connection strings so that

            // it will work with the SQLClient

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

            {

                bool successStatus;

                cleaned = null;

                try

                {

                    OleDbConnectionStringBuilder builder = new OleDbConnectionStringBuilder(connectionString);

                    builder.Remove("Provider");

                    cleaned = builder.ConnectionString;

                    successStatus = true;

                }

                catch (ArgumentException)

                {

                    successStatus = false;

                }

                return successStatus;

            }

        }

    }


    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> "8110 124th Ave SE"
                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> "8110 124th Ave SE"
                country_name=<System.String> ""
                evening_phone_number=<System.String> ""
                day_time_phone_number=<System.String> ""
                postal_code=<System.String> "98002"
                city=<System.String> "Slinghaus"
    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"
  • 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).
  • CS2002 documentation refresh

    A new refresh of the Commerce Server 2002 and Commerce Server 2002 FP1 Documentation has just been made available (this is version 5 of the CS2002 documentation).  You can download these refreshes from:


© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker