Navigation


Upcoming courses:

  • Aarhus, Denmark, March 5 - 9, 2012
  • New York City, USA, March 26 - 30, 2012
Read more on our website

About me

Brian Holmgård Kristensen

Hi, I'm Brian. I'm a Danish guy primarily working with ASP.NET e-commerce solutions using Microsoft Commerce Server.

I'm co-founder and core-member of Aarhus .NET Usergroup (ANUG), which is a offline community for .NET developers in Denmark.

You can visit my View Brian Holmgård Kristensen's profile on LinkedIn or follow me on Twitter @brianh_dk. Also please feel free to contact me via e-mail Send me an e-mail.

Categories

On this page

Only one OrderForm in Commerce Server 2009

Archive

Blogroll

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

RSS 2.0

Send mail to the author(s) E-mail

Total Posts: 36
This Year: 0
This Month: 0
This Week: 0
Comments: 10

Sign In

Follow me on Twitter @brianh_dk
 Monday, 06 September 2010

There is a built-in restriction in the new Commerce Server 2009 Foundation API (MCCF - Multi Channel Commerce Foundation) to only expect one OrderForm instance on the aggregate root, being the OrderGroup. An OrderGroup is either a Basket or PurchaseOrder (or OrderTemplate if you are using that).

Below is a simplified diagram of the key classes in the Object Model for the Orders System. Please notice that we have the OrderForms collection on the OrderGroup class, where each instance of an OrderForm can be retrieved either by index or by a name (string).

Orders API - class hierachy

This allows us to create multiple OrderForms, each with their own data like Line Items, Payments, Shipments etc, and share other data like Addresses, TrackingNumber and a few more properties on the OrderGroup class.

In all projects I’ve been working on we don’t actually use the ability to have multiple OrderForms. We only have one single OrderForm at all times.

The Commerce Server 2007 code would then look something like:

   1:  Basket basket = OrderContext.Current.GetBasket(userId, basketName);
   2:   
   3:  if (basket.OrderForms.Count == 0)
   4:      basket.OrderForms.Add(new OrderForm());

 

This retrieves a named Basket from the Orders System and if the basket is new, it will create an instance of OrderForm and add this to the OrderForms collection.

   1:  basket.OrderForms[0].LineItems.Add(
   2:      new LineItem("ProductCatalog", "ProductID", "VariantID", 1m));

 

At some point we would then like to add a Line Item to our basket as illustrated above where we hardcode the index-value to 0 to retrieve the one and only OrderForm we have.

In Commerce Server 2009 though, we never deal with the actual types, instead we work with the ICommerceEntity type. The Commerce Server 2009 code for retrieving a basket would be something like:

   1:  var query = new CommerceQuery<CommerceEntity>("Basket");
   2:   
   3:  query.SearchCriteria.Model.SetPropertyValue("UserId", userId);
   4:  query.SearchCriteria.Model.SetPropertyValue("BasketType", 0); // 0 = Basket, 1 = Purchase Order
   5:  query.SearchCriteria.Model.SetPropertyValue("Name", basketName);
   6:   
   7:  var operationServiceAgent = new OperationServiceAgent();
   8:   
   9:  var response =
  10:      operationServiceAgent
  11:          .ProcessRequest(
  12:              new CommerceRequestContext
  13:              {
  14:                  Channel = "DefaultChannel",
  15:                  UserId = Guid.NewGuid().ToString("b"),
  16:                  UserLocale = CultureInfo.CurrentCulture.ToString(),
  17:                  UserUILocale = CultureInfo.CurrentUICulture.ToString(),
  18:                  RequestId = Guid.NewGuid().ToString()
  19:              }, 
  20:              query.ToRequest())
  21:          .OperationResponses
  22:          .Single() as CommerceQueryOperationResponse;
  23:   
  24:  var basketEntity = response.CommerceEntities.Single();

 

Effectively this will execute the CommerceQueryOperation_Basket Operation Sequence defined in ChannelConfiguration.config which in short will load the Basket from the Orders System and map this to the generic ICommerceEntity type.

In the process of retrieving and mapping a Basket to a ICommerceEntity the following extension method from Microsoft.Commerce.Providers.Utility.OrderGroupExtensions is being called on the OrderGroup:

   1:  public static void EnsureDefaultOrderForm(this OrderGroup orderGroup, string modelName)
   2:  {
   3:      ParameterChecker.CheckForNull(orderGroup, "orderGroup");
   4:      if (orderGroup.OrderForms["Default"] == null)
   5:      {
   6:          if (string.IsNullOrEmpty(modelName))
   7:          {
   8:              modelName = "Basket";
   9:          }
  10:          OrderForm orderForm = CommerceServerClassFactory.CreateInstance<OrderForm>(modelName, 2, new object[] { "Default" });
  11:          orderGroup.OrderForms.Add(orderForm);
  12:      }
  13:  }

This method is responsible of making sure that a single OrderForm with the name “Default” is always available in the OrderForms collection of the OrderGroup instance.

Also there is an extension method to always retrieve this single OrderForm called Microsoft.Commerce.Providers.Utility.OrderGroupExtensions.GetDefaultOrderForm.

   1:  public static OrderForm GetDefaultOrderForm(this OrderGroup orderGroup, string modelName)
   2:  {
   3:      ParameterChecker.CheckForNull(orderGroup, "orderGroup");
   4:      if (orderGroup.OrderForms["Default"] == null)
   5:      {
   6:          if (string.IsNullOrEmpty(modelName))
   7:          {
   8:              modelName = "Basket";
   9:          }
  10:          OrderForm orderForm = CommerceServerClassFactory.CreateInstance<OrderForm>(modelName, 2, new object[] { "Default" });
  11:          orderGroup.OrderForms.Add(orderForm);
  12:      }
  13:      return orderGroup.OrderForms["Default"];
  14:  }

This method is used throughout the many Operation Sequence Components in the Foundation API and if you are developing your own custom Operation Sequence Components that works on the Orders System this method is properly something you would like to use.

As mentioned earlier we’ve just been using one OrderForm in all our Commerce Server projects, so this new limitation is not a problem for us, but on one of my Commerce Server Training courses I had a guy telling me that they where actually using multiple OrderForms on a CS 2007 project, so this new limitation would be a problem for them if they were to upgrade or create a similar solution on a new CS 2009 project.

What if we need more than OrderForm on our project, what to do?

In short: rethink. A solution with multiple OrderForms in CS 2009 will be too difficult to implement because of the many dependencies in the standard Operation Sequence Components that expecting there to be only one – remember they are all calling the GetDefaultOrderForm() extension method. Consider using multiple OrderGroups instead.

 

If you are reading this and have come up with a better solution to having multiple OrderForms in CS 2009 or have any comments at all I would really appreciate hearing from you :-)

Posted on Monday, 06 September 2010 07:54:00 (Romance Standard Time, UTC+01:00)
# | Comments [0]