<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel>
    <title>Max Akbar's Commerce Server Blog</title>
    <link>http://www.maxakbar.com</link>
    <description>For the hardcore Commerce Server Developer...</description>
    <language>en-us</language>
    <lastBuildDate>9/3/2010</lastBuildDate>
    <item>
      <title>Commerce Server Staging (CSS) and Catalogs</title>
      <link>http://www.maxakbar.com/blog.aspx?id=34</link>
      <description>&lt;p&gt;A few things you didn’t know about CSS and how catalogs move from one environment to another. The process of using the CSS is pretty simple just use the MMC console for CSS and setup your project but there are some undocumented and some scenarios that will cause you some issues that you need to be aware. 
&lt;h3&gt;So will I sing praise unto thy name for ever. that my Commerce Server site may daily perform&lt;/h3&gt;
&lt;p&gt;Someone had asked as to why his relationship would not move form one environment to another and I didn’t dive too deep into it and I couldn’t help him. As it turns out that my current client run into something very similar. So did some work and found out the reason.&lt;/p&gt;
&lt;p&gt;Here is the scenario, have two catalogs in catalog one create a relationship add items form catalog two. Now setup a CSS job that will move your items from one server to another but choose catalog one. The job should be expression based. The relationship will not move by default. If you look there are three values that can be set for an expressional export None, Immediate Children and All Levels. If you select either Immediate Children or All Levels only then your relationship will be moved to the target environment. &lt;/p&gt;
&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="exportoptions" border="0" alt="exportoptions" src="http://maxakbar.com/assets/images/blog/exportoptions.png" width="300" height="334"&gt; &lt;/p&gt;
&lt;p&gt;The reason is simple you setup a relationship between two different catalogs but you select only one to move so you have to be explicit on what the export should do.&lt;/p&gt;
&lt;p&gt;Another issue I have noticed is that when running CSS to move products is overwriting hierarchies and relationships. When you use the Catalog Manager this feature is available.&lt;/p&gt;
&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="relationships" border="0" alt="relationships" src="http://maxakbar.com/assets/images/blog/relationships.png" width="388" height="286"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;But this option is missing when using CSS. It’s true that this option is not available through the UI but you can modify this using the project XML. When you create projects using CSS the project properties are created in the registry and xml file if using the data project. The project files are stored in “C:\Program Files\Microsoft Commerce Server 2007\Staging\Projects” if Commerce Server is installed using defaults. In the xml file there is an ImportOption that is set to Yes=True by default but you change this behavior.&lt;/p&gt;
&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="projectfile" border="0" alt="projectfile" src="http://maxakbar.com/assets/images/blog/projectfile.png" width="499" height="341"&gt; &lt;/p&gt;
&lt;p&gt;Now an over all look on the Import option for over writing category hierarchy and relationships. The product is using two catalog features but have only one option what if you wanted to overwrite your relationships but not your category hierarchy or the other way around, well your out of luck. Here is another scenario where things will get a bit tricky what if you only wanted to export your price property? In this case you would setup your CSS and set the property import option to overwrite relationship and category hierarchy to true. The exported XML file will only have one property the price. When you do the import the primary parent category will be removed if you had setup primary category with your product. So why does this happen? The reason is simple the primary parent category is setup as a property with the product when the export happens it exports all the parent categories and when an import happens the primary parent is removed because we have parent categories and setup to over write relationships.&lt;/p&gt;</description>
      <guid>34</guid>
    </item>
    <item>
      <title>Hacking Commerce Server Staging Part III</title>
      <link>http://www.maxakbar.com/blog.aspx?id=33</link>
      <description>&lt;p&gt;As promised here is the code for the previous post on hacking the CSS engine.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.maxakbar.com/downloads/CSSTestUI.zip"&gt;Download Code…&lt;/a&gt;&lt;/p&gt;</description>
      <guid>33</guid>
    </item>
    <item>
      <title>Hacking Commerce Server Staging Part II</title>
      <link>http://www.maxakbar.com/blog.aspx?id=32</link>
      <description>&lt;p&gt;In the previous post I showed you how to create a custom UI for the Commerce Server Staging (CSS). In this post I will show you how you can create a custom handler that will fire and perform some action based on the custom UI.&lt;/p&gt;
&lt;h3&gt;Custom Handler&lt;/h3&gt;
&lt;p&gt;As noted in previous post CSS uses managed code for data import\exports. CSS engine works on using a factory object to create handlers depending on the project type name. The project type name is specified in the “BusinessDataTypes.xml” file located in “C:\Program Files\Microsoft Commerce Server 2007\Staging\Bin\” folder if Commerce Server was installed with defaults. In my sample I have a custom name called “Max's Test”. When the CSS engine identifies an export or import it reads the “BusinessDataTypes.xml” file then look at the project xml file and finds the type identified. So our project xml file should have “Max's Test” as the BusinessDataTypeName attribute. When the match is made the CSS engine will load the “HandlerAssemblyQualifiedName” attribute value. In the sample “CSSTestUI.CustomHandler” is the handler. The CustomHandler class inherits from IBusinessDataStagingHandler having two methods for implementation Import\Export.&lt;/p&gt;
&lt;p&gt;Let’s take a look at a simple implementation:&lt;/p&gt;
&lt;table border="1" cellspacing="1" cellpadding="1" width="100%"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign="top"&gt;
&lt;p&gt;class CustomHandler : IBusinessDataStagingHandler&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region IBusinessDataStagingHandler Members 
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void Export(string projectName, BusinessData businessData, string projectLocation, string sourceSite)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (projectName == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("projectName");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (businessData == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("businessData");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (projectLocation == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("projectLocation");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (sourceSite == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("sourceSite");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; string filename = Path.Combine(projectLocation, businessData.BusinessDataId + ".xml");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; StreamWriter st = File.CreateText(filename);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; st.Write("From Custom handler (Export)...");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; st.Close();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } 
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void Import(string projectName, BusinessData businessData, string projectLocation, string destinationSite)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (businessData == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("businessData");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (projectLocation == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("projectLocation");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (destinationSite == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("destinationSite");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; string filename = Path.Combine(projectLocation, businessData.BusinessDataId + ".xml");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; StreamWriter st = File.AppendText(filename);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; st.Write("From Custom handler (Import)...");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; st.Close();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } 
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion&lt;br&gt;}&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;In the sample above instead of doing real work I am just writing and reading the xml project data file. Please note I am not writing xml so if you open it in a xml browser you will generate errors.&lt;/p&gt;
&lt;h3&gt;Theda theda that’s all folks&lt;/h3&gt;
&lt;p&gt;Once you create your own custom handler just make sure to sing the assembly and GAC it. Then you need to stop\start the CSS Service before the project works. To debug your code you would attach to the MMC console for the UI and the CSS Service for the handler.&lt;/p&gt;
&lt;p&gt;Good luck creating cool custom CSS projects.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Once I have access to ftp I will upload the project files in these blog posts. The project was created VS2008 and tested on windows 2008\Commerce Server 2007. There should be no issues with Commerce Server 2009 if you do find issues please send me an email so I can post it for others.&lt;/p&gt;</description>
      <guid>32</guid>
    </item>
    <item>
      <title>Hacking Commerce Server Staging</title>
      <link>http://www.maxakbar.com/blog.aspx?id=30</link>
      <description>&lt;p&gt;Way back when I was a program manger on the Commerce Server Product Group one of my features was Commerce Server Staging (CSS). While going over CSS with the dev team and PMs I wanted to make CSS extensible so customers could create their own CSS projects. But as is with everything else this decision was met with “We don’t have time and resources” and it was dropped.&lt;/p&gt;
&lt;p&gt;The dev manager thought it was good idea and stated that he would keep the APIs public that way in the next version of Commerce Server they could revisit the subject. Here we are with the new version and no extensibility. Now as you know the CS product has gone through much turn over and that dev manager is with a different team with MS. &lt;/p&gt;
&lt;p&gt;In this post I am going to show you how you could hack CSS and build your own custom projects.&lt;/p&gt;
&lt;h3&gt;CSS UI Basics&lt;/h3&gt;
&lt;p&gt;CSS UI is only visible using the MMC console. CSS is a windows service but there are APIs that talk to the service. The API support COM as well as .NET (COM wrappers) that allow you to pretty much do everything that you can using MMC.&amp;nbsp; Having COM means you can write VBScript code for automation (note the Java Script is not supported due to Java script not supporting parameter passing values by ref).There is also a command line tool and once again it almost does everything MMC can.&lt;/p&gt;
&lt;p&gt;But this section is about the UI so lets talk about that. The Business Data UIs of CSS is written in .NET. So there is a whole framework that handles this for you. Which means the MMC loads .NET controls when you open a project or create one using the wizard. How does CSS know which tabs to load on the project properties? CSS when installed creates a folder in the Root of Commerce Sever “%COMMERCE_SERVER_ROOT%” called staging. In the staging folder there a sub folder called bin. In the bin folder there is an xml file BusinessDataTypes.xml that holds the types of business data that CSS support.&lt;/p&gt;
&lt;p&gt;If you look into the content of the BusinessDataTypes.xml file (see table below) notice that you have Handlers and UIProgIDs. The UIProgIDs are used to load controls onto project tabs. The Handlers are used to export and import data when the project is executed.&lt;/p&gt;
&lt;table border="1" cellspacing="1" cellpadding="1" width="100%"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign="top"&gt;
&lt;p&gt;&amp;lt;?xml version="1.0" ?&amp;gt; &lt;br&gt;&amp;lt;BusinessDataTypes&amp;gt;&lt;br&gt;&amp;nbsp; &amp;lt;BusinessDataType Name ="Orders"&amp;nbsp; HandlerAssemblyQualifiedName = "Microsoft.CommerceServer.Staging.OrdersHandler, Microsoft.CommerceServer.Staging.BusinessDataStagingFramework, Version=6.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"&amp;nbsp; UIProgID = "Microsoft.CommerceServer.Staging.UI.OrdersConfigurationPropertyPageControl" /&amp;gt;&lt;br&gt;&amp;nbsp; &amp;lt;BusinessDataType Name ="SiteTerms"&amp;nbsp; HandlerAssemblyQualifiedName = "Microsoft.CommerceServer.Staging.SiteTermHandler, Microsoft.CommerceServer.Staging.BusinessDataStagingFramework, Version=6.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"&amp;nbsp; UIProgID = "Microsoft.CommerceServer.Staging.UI.SiteTermsPropertyPageControl" /&amp;gt;&lt;br&gt;&amp;nbsp; &amp;lt;BusinessDataType Name ="Marketing"&amp;nbsp; HandlerAssemblyQualifiedName = "Microsoft.CommerceServer.Staging.MarketingHandler, Microsoft.CommerceServer.Staging.BusinessDataStagingFramework, Version=6.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"&amp;nbsp; UIProgID = "Microsoft.CommerceServer.Staging.UI.MarketingPropertyPageControl" /&amp;gt;&lt;br&gt;&amp;nbsp; &amp;lt;BusinessDataType Name ="Catalog" HandlerAssemblyQualifiedName = "Microsoft.CommerceServer.Staging.CatalogHandler, Microsoft.CommerceServer.Staging.BusinessDataStagingFramework, Version=6.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" UIProgID = "Microsoft.CommerceServer.Staging.UI.CatalogControl" /&amp;gt;&lt;br&gt;&amp;lt;/BusinessDataTypes&amp;gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;So can you create your own UI? Sure why not. I will show you a quick sample which I will outline in this post. &lt;/p&gt;
&lt;h3&gt;Create CSS Custom UI&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The first thing you want to do is create a project in Visual Studio and select Class Library.&lt;/p&gt; 
&lt;li&gt;&lt;p&gt;Step two add references by implementing the IBusinessDataUserInterface which exists in the “C:\Program Files\Microsoft Commerce Server 2007\Assemblies\CSStagingUserInterfaces.dll” assembly if commerce server was installed in it’s default location. Please note that this is also GACed. The next reference is Microsoft.CommerceServer.Staging.BusinessDataStagingFramework.dll also located in the same directory and GACed.&lt;/p&gt; 
&lt;li&gt;&lt;p&gt;Now that you have the two references you will need to add a Control to your project and have it inherit IBusinessDataUserInterface and implement all the interface. Your class should look like the image below:&lt;br&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="ClassImage" border="0" alt="ClassImage" src="http://maxakbar.com/assets/images/blog/ClassImage.png" width="801" height="234"&gt;&amp;nbsp;&lt;br&gt;Notice the class attribute make sure that you have the same with your own unique Guid.&lt;/p&gt; 
&lt;li&gt;&lt;p&gt;Before we can actually write code to our UI we need to add registration code:&lt;/p&gt;&lt;br&gt;
&lt;table border="1" cellspacing="1" cellpadding="1" width="100%"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign="top"&gt;
&lt;p&gt;#region Component Registration 
&lt;p&gt;[ComRegisterFunction]&lt;br&gt;private static void ComRegister(Type t)&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string name = @"CLSID\" + t.GUID.ToString("B");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(name, true))&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; key.CreateSubKey("Control").Close();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; using (RegistryKey key2 = key.CreateSubKey("MiscStatus"))&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; key2.SetValue("", "131457");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; using (RegistryKey key3 = key.CreateSubKey("TypeLib"))&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; key3.SetValue("", Marshal.GetTypeLibGuidForAssembly(t.Assembly).ToString("B"));&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; using (RegistryKey key4 = key.CreateSubKey("Version"))&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Version version = t.Assembly.GetName().Version;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; string str2 = string.Format("{0}.{1}", version.Major, version.Minor);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (str2 == "0.0")&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; str2 = "1.0";&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; key4.SetValue("", str2);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;} 
&lt;p&gt;[ComUnregisterFunction]&lt;br&gt;private static void ComUnregister(Type t)&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string subkey = @"CLSID\" + t.GUID.ToString("B");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Registry.ClassesRoot.DeleteSubKeyTree(subkey);&lt;br&gt;} 
&lt;p&gt;#endregion Component Registration&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;li&gt;&lt;p&gt;Ok now we are ready to populate our interface implementations. For the ModuleName replace the text to with your own custom name. The wizardMode variable is used when creating projects using the wizard. When creating a project using the wizard mode you will not see your custom control as the UI for the process is hard coded to only display the four Commerce Sever Business Types. But you can view your control using non wizard mode. The modeReadOnly is used to distinguish between Operator and Administrator. Remember an Operator can not modify project properties.&lt;br&gt;Private variables:&lt;/p&gt;&lt;br&gt;
&lt;table border="1" cellspacing="1" cellpadding="1" width="100%"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign="top"&gt;
&lt;p&gt;internal const string ModuleName = "Max's Test";&lt;br&gt;private BusinessDataCollection businessDataCollection;&lt;br&gt;private bool modeReadOnly;&lt;br&gt;private bool wizardMode;&lt;br&gt;private BusinessData businessData;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br&gt;&lt;p&gt;Flush Method:&lt;/p&gt;&lt;br&gt;
&lt;p&gt;
&lt;table border="1" cellspacing="1" cellpadding="1" width="100%"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign="top"&gt;
&lt;p&gt;public void Flush()&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (int i = this.businessDataCollection.Count - 1; i &amp;gt;= 0; i--)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; BusinessData businessData = this.businessDataCollection[i];&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!(businessData.BusinessDataTypeName != ModuleName))&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.businessDataCollection.Remove(businessData);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;}&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;
&lt;p&gt;InitializeSate Method:&lt;/p&gt;
&lt;table border="1" cellspacing="1" cellpadding="1" width="100%"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign="top"&gt;
&lt;p&gt;public void InitializeSate(string siteName, Microsoft.CommerceServer.Staging.BusinessDataCollection collection, bool modeReadOnly)&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (siteName == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("siteName");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (collection == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("collection");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.modeReadOnly = modeReadOnly;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.businessDataCollection = collection; 
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.businessData = GetFirstBusinessData(collection, ModuleName);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (this.businessData == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.businessData = new BusinessData();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.businessData.BusinessDataTypeName = ModuleName;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.businessData.BusinessDataId = Guid.NewGuid(); 
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; BusinessDataOption opt = new BusinessDataOption("checkBox1", checkBox1.Checked.ToString());&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.businessData.ExportOptions.Add(opt); 
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; BusinessDataOption opt2 = new BusinessDataOption("textBox1", textBox1.Text);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.businessData.ExportOptions.Add(opt2); 
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.businessDataCollection.Add(this.businessData);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; string opt = Get(this.businessData.ExportOptions, "checkBox1");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; string opt2 = Get(this.businessData.ExportOptions, "textBox1"); 
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; checkBox1.Checked = Convert.ToBoolean(opt);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; textBox1.Text = opt2;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;}&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;br&gt;SaveState:&lt;br&gt;&lt;/p&gt;
&lt;table border="1" cellspacing="1" cellpadding="1" width="100%"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign="top"&gt;
&lt;p&gt;public void SaveState()&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!this.modeReadOnly)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // put code for read only&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // We will assume administrator&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; BusinessDataOption opt = GetOption(this.businessData.ExportOptions, "checkBox1");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; opt.Value = checkBox1.Checked.ToString(); 
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; BusinessDataOption opt2 = GetOption(this.businessData.ExportOptions, "textBox1"); &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; opt2.Value = textBox1.Text;&lt;br&gt;}&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;br&gt;WizardMode:&lt;br&gt;&lt;/p&gt;
&lt;table border="1" cellspacing="1" cellpadding="1" width="100%"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign="top"&gt;
&lt;p&gt;public bool WizardMode&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; set&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.wizardMode = value;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;}&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;br&gt;Helper Methods:&lt;br&gt;&lt;/p&gt;
&lt;table border="1" cellspacing="1" cellpadding="1" width="100%"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign="top"&gt;
&lt;p&gt;internal static BusinessData GetFirstBusinessData(BusinessDataCollection collection, string type)&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (BusinessData data in collection)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (data.BusinessDataTypeName == type)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return data;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return null;&lt;br&gt;} 
&lt;p&gt;internal static BusinessDataOption GetOption(BusinessDataOptionCollection options, string optionName)&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (BusinessDataOption option in options)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (option.Name == optionName)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return option;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return null;&lt;br&gt;} 
&lt;p&gt;internal static string Get(BusinessDataOptionCollection options, string optionName)&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (options == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("options");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (optionName == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("optionName");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (BusinessDataOption option in options)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (option.Name == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("option");&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (option.Name.Trim().ToUpper(CultureInfo.InvariantCulture) == optionName.ToUpper(CultureInfo.InvariantCulture))&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (option.Value == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException(optionName);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return option.Value.Trim().ToUpper(CultureInfo.InvariantCulture);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return null;&lt;br&gt;}&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;li&gt;
&lt;p&gt;Ok now that we have our code lets add a new control as we referenced a checkbox and textbox.&lt;br&gt;&lt;img style="border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px" title="ProjectImage" border="0" alt="ProjectImage" src="http://maxakbar.com/assets/images/blog/ProjectImage.png" width="689" height="394"&gt;&lt;/img&gt;&lt;/p&gt;
&lt;li&gt;
&lt;p&gt;Compile your project and make sure to sign the assembly as will add it to the GAC.&lt;/p&gt;
&lt;li&gt;
&lt;p&gt;Modify the BusinessDataTypes.xml file in “C:\Program Files\Microsoft Commerce Server 2007\Staging\Bin” to reflect the GACed assembly.&lt;br&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="xmlfile" border="0" alt="xmlfile" src="http://maxakbar.com/assets/images/blog/xmlfile.png" width="861" height="159"&gt;&lt;/p&gt;
&lt;li&gt;
&lt;p&gt;GAC the assembly and stop and restart the CSS service.&lt;/p&gt;
&lt;li&gt;
&lt;p&gt;Now open CSS MMC and create a project not using the wizard.&lt;br&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="CustomProject" border="0" alt="CustomProject" src="http://maxakbar.com/assets/images/blog/CustomProject.png" width="419" height="495"&gt; &lt;br&gt;Notice that we have our control in the project properties. I have not figured out how to publish the custom control name to the tab, but all works. Add some values in your custom control tab and other project properties such as site name and destination. Select OK and save your project. Now examine the xml file that is created for your project.&lt;br&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="projectxml" border="0" alt="projectxml" src="http://maxakbar.com/assets/images/blog/projectxml.png" width="768" height="125"&gt;&amp;nbsp;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;As you modify the project properties the settings will be saved in the project xml file. Notice that the options are ExportOption name\value. You can also have ImportOptions. In the SaveState method I added code to save the control options in ExportOptions collection you can if you have values that need to be saved for import in the ImportOptions collection.&lt;br&gt;Ok that’s it for now in the next post I will show you how to create your own handler that will get fired for your custom control.&lt;/p&gt;</description>
      <guid>30</guid>
    </item>
    <item>
      <title>Catalog Performance Tip</title>
      <link>http://www.maxakbar.com/blog.aspx?id=27</link>
      <description>&lt;p&gt;You may notice over time that your site is slow specifically the Catalog calls. In this post I hope to address some performance improvements by doing adding a maintenance task.&lt;/p&gt;
&lt;h3&gt;Catalog System&lt;/h3&gt;
&lt;p&gt;I am not going to tell you what the Catalog System is&amp;nbsp; you can always find info in the help files but I will explain some of the internals that slows down over time. Looking at how Commerce Server retrieve data is a bit interesting. The Catalog System has two databases one Your_SiteName_ProductCatalog and another MCSC_CatalogScratch.&lt;/p&gt;
&lt;p&gt;All of the Catalogs, Categories, Products and their relationship is held in Your_SiteName_ProductCatalog database. The MCSC_CatalogScratch is a persisted temporary storage. Some Catalog APIs when called internally need to store their data into temp tables and then do a select of that. Any time you perform a search or use paganation among other calls the temporary location is used.&lt;/p&gt;
&lt;h3&gt;MSCS_CatalogScratch Database&lt;/h3&gt;
&lt;p&gt;So what is this database? The thought behind this database was the right idea but used incorrectly. If you have written advanced stored procedures you have at one time or another used temp tables. The creation of temp tables are a performance hit. So what the Commerce Server product did was to create a temp database and create it’s temp table in that database. So a table is created when a query is made and the next request that comes a long will do a quick search of system tables to see if a table already exists if so then it will use it else it will create a new table. Over time you have have thousands of tables but that’s not the only bad part. In some Catalog System stored procedures (which I have done sql traces) I have realized that they used hints like KEEPFIXED PLAN. Since multiple queries of different type use these tables it’s possible that you get a plan that is not very optimized and slow down the execution of the stored procedure.&lt;/p&gt;
&lt;h3&gt;You are a diseases and I am the cure&lt;/h3&gt;
&lt;p&gt;So how do you fix this. Well you really can’t touch the Commerce Server stored procedures but you can delete the temp tables to help performance. You should ideally have a job\task that periodically goes and deletes these tables. The VBScript that cleans out these tables is located in “C:\Program Files\Microsoft Commerce Server 2007\Tools\CatalogCleanup.vbs” if Commerce Server was installed using defaults. But you don’t have to use the VBScript just use the stored procedure that it calls. &lt;/p&gt;
&lt;p&gt;EXEC dbo.ctlg_DropPersistentTablesInScratchDB 0&lt;/p&gt;
&lt;p&gt;EXEC dbo.ctlg_DropPersistentTablesInScratchDB 1&lt;/p&gt;
&lt;p&gt;There are two values you can pass it zero and one. I can’t remember exactly but if you use the zero value it will only delete tables that are not currently being used. If you pass one then all tables are deleted regardless if they are being used or not. I have done this with some customers who have had over several thousand tables and the stored procedure returned errors not to worry just keep running the stored procedure until you have not errors.&lt;/p&gt;</description>
      <guid>27</guid>
    </item>
    <item>
      <title>No comment!!!</title>
      <link>http://www.maxakbar.com/blog.aspx?id=26</link>
      <description>&lt;p&gt;I have been asked as to why the comment section of my blog is turned off. It seems that a porn site is trying to up their rating so they posted comment with links. It was becoming a headache to manage so I turned them off. It’s not that I don’t want you to comment I just don’t want to promote porn :). If you have a comment or question please send them to maximum2000 AT hotmail DOT com. &lt;/p&gt;</description>
      <guid>26</guid>
    </item>
    <item>
      <title>So should I or shouldn't...</title>
      <link>http://www.maxakbar.com/blog.aspx?id=24</link>
      <description>&lt;p&gt;I have always been asked the question of moving to CS2009 or staying with CS2007. Currently there are two versions CS2009 and CS2009\R2 which can make the choice even more difficult. Before I go through the benefits of the different version let me just come right out and say it.&lt;/p&gt;
&lt;p&gt;I have never been a big fan of CS2009, the reason is that CS2009 was supposed to be a solution accelerator and now it has been made into a product. I believe that it is far from a complete product :(. If you go over the Microsoft site and read the benefits of CS2009 Microsoft is going to give a glass of fruit punch and once you drink, you are going to see rainbows everywhere you look. The only benefit I can find with CS2009 is that you get an extended life support.&lt;/p&gt;
&lt;h3&gt;SharePoint Integration&lt;/h3&gt;
&lt;p&gt;What about the SharePoint integration? Sorry, you could have done that with CS200x it’s a matter of modifying the web.config to make the integration happen. Well how about the WebParts? You don’t need SharePoint to have WebParts integration but you do get the source code in the new template site of CS2009 which forces you to use SharePoint. I have looked at the WebParts and they are as complicated to understand as the previous StarterSite :(. It’s a fine line between performance and architecture. Sometime you just need to put a nail in a board, no need to get fancy just get a hammer and drive the nail in.&lt;/p&gt;
&lt;h3&gt;New API&lt;/h3&gt;
&lt;p&gt;What about the new API isn’t it cool having a unified &lt;strike&gt;theory&lt;/strike&gt; err… API? I have worked with the new API and I am sorry to say it’s much harder to work with and longer lines of code to write. The only benefit I can see is with R2 where you can have multiple tier architecture. But remember that will come with a cost so even if you are on one server for presentation and Business Logic you will have interprocessing which is expensive and degrade performance. Now some folks at the Product Group have been bold enough to tell me that the new CS2009 API are faster than the old. I find this very hard to believe. The reason is that the new API is built on top of the old API they are not going directly to the CS stored procedures so how in the world can the new API be faster. &lt;/p&gt;
&lt;h3&gt;New Feature of CS2009&lt;/h3&gt;
&lt;p&gt;Doesn’t CS2009 give you any new features? Of course it does. Customer can leave feedback, cool huh. Not really, the mechanism of leaving feedback is only if you have SharePoint integrated because that feedback\comment data is stored in SharePoint you can’t use it on a none SharePoint site.&lt;/p&gt;
&lt;h3&gt;Break Down&lt;/h3&gt;
&lt;p&gt;So what does CS2009 give you:&lt;/p&gt;
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;SharePoint Integration 
&lt;li&gt;Unified API 
&lt;li&gt;Product Feedback\Comment\Rating 
&lt;li&gt;CS2009\R2 multi tier architecture 
&lt;ul&gt;
&lt;li&gt;Remember CS2009\R2 is 64 bit only&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;Has been said that CS2009 has bug fixes that CS2007 does not (I have not found a list of these bugs :() 
&lt;ul&gt;
&lt;li&gt;WTF, are you kidding me&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;Longer Product Life Support &lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Please correct me if I am wrong on any of these points or missing something crucial. &lt;/p&gt;
&lt;h3&gt;Bottom Line&lt;/h3&gt;
&lt;p&gt;If you have CS2007 then stay on it no need unless you come to end of life of the product then upgrade. The upgrade will be simple just install CS2009 and your old API will work. None of the old API has changed.&lt;/p&gt;
&lt;p&gt;If your business need to have multi tier architecture then go for CS2009\R2 when it’s RTMed.&lt;/p&gt;</description>
      <guid>24</guid>
    </item>
    <item>
      <title>Real Time Inventory? Hmm?</title>
      <link>http://www.maxakbar.com/blog.aspx?id=25</link>
      <description>&lt;p&gt;Does Commerce Server support real time inventory system? That’s the question of the day and I hope to shed some light on this subject.&lt;/p&gt;
&lt;h3&gt;Commerce Server Inventory System&lt;/h3&gt;
&lt;p&gt;The Inventory is a bit different than the other Systems in Commerce Server. In order to use the Inventory System you have to have the Catalog System but the other way is not true. You can have a Catalog System with no Inventory. Even thought there is a relationship between Inventory and Catalog they are two different systems. At least that’s what I used to think.&lt;/p&gt;
&lt;p&gt;If you pay attention to the documentation of Commerce Server it’s not very clear about how closely integrated the two systems are. When caching of Catalog System is turned on then the Product object will cache the Inventory data. But what if I want to call the Inventory API so you can only get the Inventory data. What happens then? Well true believers you get the data from cache! Say what? Yes you get the data from the cache. What if I call the Refresh method? Nope, sorry that only refreshes the Inventory object not make a trip back to the database. &lt;/p&gt;
&lt;h3&gt;Commerce Server’s Real Time Inventory&lt;/h3&gt;
&lt;p&gt;So how in the world can Commerce Server be real time? The UpdateInventory and CheckInventory pipeline components are real time as they go to the database and call the stored procedures directly. In fact the documentation only notes that these components are real time.&lt;/p&gt;
&lt;h3&gt;So how do I get the inventory from the database? &lt;/h3&gt;
&lt;p&gt;Sadly,&amp;nbsp; you can’t. You have either wait for the data to fall of the cache or create your own stored procedure to fetch the data. A bit disappointing that you have to write custom call to check the inventory levels :(. By the way I looked at how difficult it would be to change this and it’s just an override boolean internally with the Inventory object. The Inventory code is hard coded to check the cache first. Say what!&lt;/p&gt;</description>
      <guid>25</guid>
    </item>
    <item>
      <title>When the gun goes bang bang bang, who's gonna know who's the one?</title>
      <link>http://www.maxakbar.com/blog.aspx?id=23</link>
      <description>Since I am finishing up my business in the next few months I thought it would be best to go over some of the issues that my customers always struggling with. Bad Design and Performance and of the two I have spent most of my time with Performance tuning. I will also go over some of the most frequent questions I am asked the biggest one should I use CS2009 or CS2007. I will try to be as honest and open your eyes to CS2009. Stay tuned and as I get time I will post these two blogs. They won’t be the last but they are very important. </description>
      <guid>23</guid>
    </item>
    <item>
      <title>Got Marketing!</title>
      <link>http://www.maxakbar.com/blog.aspx?id=22</link>
      <description>&lt;p&gt;When the first request is made to a Commerce Server site Commerce Server 
loads it&amp;#39;s modules and populate it&amp;#39;s caches based on the configuration of 
web.config. One of these modules and Cache that can be modified is the Marketing 
data.&lt;/p&gt;
&lt;h3&gt;Marketing Runtime&lt;/h3&gt;
&lt;p&gt;Commerce Server loads it&amp;#39;s Marketing data (Ads and discounts) in one shot by 
calling mktg_spRuntimeLoadDiscounts stored procedure. You can change this 
behavior by having your own stored procedure called. Why would you want to do 
that maybe&amp;nbsp; you want additional columns to be returned or have a staging 
environment and you want all discounts that are active and not active to be 
evaluated. Just make sure that you not omit any columns and records that the 
original stored procedure returns.&lt;/p&gt;
&lt;h3&gt;Change the default behavior of loading Marketing data&lt;/h3&gt;
&lt;table style="width: 100%" cellspacing="1" class="style1"&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;p&gt;Modify the web.config by adding a  &amp;lt;config&amp;gt; element to the &amp;lt;cache&amp;gt;:
 &lt;config&gt;
    &amp;lt;key="LoadDiscountsProcedure" value="myProcedure"/&amp;gt;
&lt;/config&gt;
Note that myprocedure should have the same signature as the default mktg_spRuntimeLoadDiscounts procedure.
&lt;/p&gt;&lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
</description>
      <guid>22</guid>
    </item>
  </channel>
</rss>