by community-syndication | Mar 9, 2006 | BizTalk Community Blogs via Syndication
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.
by community-syndication | Mar 5, 2006 | BizTalk Community Blogs via Syndication
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”
by community-syndication | Mar 4, 2006 | BizTalk Community Blogs via Syndication
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).