Upgrade from CMS 6R2 to EPiServer 7 CMS and from EPiServer Community 4.1 to EPiServer Community 7

There is a requirement before upgrading a Community site with separate databases (CMS6r2 and Community 4.1) to EPiServer 7 and Community 7 is to merge the Community database with the CMS database. This is an instruction of how to accomplish this in MS SQL Server 2008 R2.

1. Startup
In the SSMS, right-click the Community database that shall be merged with the CMS database and generate a script.

2. Choose Objects
Select  “Select specific database objects” and then select Tables, Views, Stored Procedures and User-Defined Functions but not all objects within those boxes.  Objects to choose:

Tables
tblEPiServerCommon*
tblEPiServerCommunity*

Views
vwEPiServerCommon*
vwEPiServerCommunity*

Stored Procedures
spEPiServerCommon*
spEPiServerCommunity*

User-Defined Functions
fnEPiServerCommon*
fnEPiServerCommunity*
3. Set Scripting Options
Save the script to a specific location and save to a single file. Then press the “Advanced button”.
4. Advanced Scripting Options
General: Set “Types of data to script” to “Schema and data”.
Table/View Options: Set all to “True”.
5. Summary
Review your settings.
6. Save or Publish Scripts
The report is shown.
7. Execute the script file on the CMS database
Execute the script file that is generated (e.g. script.sql) on the CMS database.  Open the file in the SSMS. In the beginning of the file set USE [yourCMSDatabaseName] and then execute the script. Review your CMS database and verify that the objects have been transferred.
8. Configuration
In connectionStrings.config, change the connection string for the Mail database to use the CMS database. Test the site and verify that it runs correctly.
9. Upgrade
Upgrade from CMS 6R2 to EPiServer 7 CMS and from EPiServer Community 4.1 to EPiServer Community 7.
Information can be obtained from EPiServer Support.

Working with Markets in EPiServer Commerce 7.5

It is a very strong feature of EPiServer Commerce 7.5 being an Enterprise Commerce Platform combined with the power of all CMS features. It can help businesses to grow and target correct markets and earn more profits. The “Market” means that you can define multiple markets, each with its own product catalog, language, currency, and promotions, for a single-site. It can be any type of division of Business, e.g. For a Business there can be more than one markets within the same country, language or a currency or another business may divide its markets at country level. E.g.
A Book Seller Company may be selling different type of books in different parts of countries and they may require two different sites/markets or a car seller company selling cars in different countries
Implementing markets
You can define your own markets by implementing the IMarket interface, and set up a list of supported languages (through CultureInfo), countries in that market, supported currencies, as well as the default language and currency to be used. Through the use of the ICurrentMarketinterface, you can easily get the current market throughout the application. The ICurrentMarket interface should be registered at the initialization step of your application, and this can be done by implementing IConfigurableModule. E.g.
public class AustralianMarket: ICurrentMarket
{}
public class MarketConfigs : IConfigurableModule
public void ConfigureContainer(ServiceConfigurationContext context)
{
context.Container.Configure(ce =>
{
ce.For<ICurrentMarket>().Singleton().Use<AustralianMarket>();
});
}

Getting all available markets
// Get all available markets.
ICurrentMarket _currentMarketService = ServiceLocator.Current.GetInstance<ICurrentMarket>();
var marketStorage = _currentMarketService as MarketStorage;
var listMarket = marketStorage.GetAvailableMarkets();
Getting current market
public ICurrentMarket CurrentMarket{
    get{
        if(currentMarket==null)
        {
        var _currentMarketService = ServiceLocator.Current.GetInstance<ICurrentMarket>();
        currentMarket = _currentMarketService.GetCurrentMarket();
        }
        return currentMarket;
    }
}
Setting current market
// Set current markets.
var _currentMarketService = ServiceLocator.Current.GetInstance<ICurrentMarket>();
var marketA = _currentMarketService as AustralianMarket;
marketA.SetCurrentMarket(YourMarketId);
Getting Carts
To implement market dependent carts, you can use the CartHelper constructor with the last one as an instance of IMarket.
CartHelper(string name, Guid userId, IMarket market)

Getting Saleprice
public  Price GetSalePrice(Entry entry, decimal quantity)
{
    return StoreHelper.GetSalePrice(entry, quantity, CurrentMarket);

}

CMS Style rendering Templates in EPiServer Commerce 7.5

1.       Create a Content Type
We can use CMS-style rendering template in EPiServer Commerce 7.5. to use rendering template for a Node or an Entry, we need to define a content type class e.g.
using EPiServer.Commerce.Catalog.ContentTypes;
using EPiServer.Commerce.Catalog.DataAnnotations;
using EPiServer.DataAnnotations;
namespace EPiServer.Commerce.XYZ
{
    [ContentType]
    public class FashionItemContent : VariationContent
    {
        [Encrypted]
        [CultureSpecific]
        public virtual string Description { get; set; }
        [SaveHistory]
        public virtual int Size { get; set; }
    }
}
2.       Define templates
It is possible to have several templates defined for the same model. If you want to display a Node/Entry on your site, you can do so by creating a template in the same way as we do with CMS content. e.g.
[TemplateDescriptor(Default = true)]
public partial class DefaultFashionItemTemplate : BlockControlBase<FashionItemContent>
{ }
[TemplateDescriptor(Tags = new string[] { EPiServer.Framework.Web.RenderingTags.Sidebar })]
public partial class SidebarFashionItemTemplate : BlockControlBase<FashionItemContent>
{ }
In MVC to render a ContentArea property you can specify the tag by using Tag attribute as follows
<% Html.PropertyFor(m => m.MyContentArea, new { Tag = EPiServer.Framework.Web.RenderingTags.Sidebar })%>
3. Registering new routing
To use new renderer template, you need to register new routing mode.
using System.Web.Routing;
using EPiServer.Commerce.Routing;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
namespace EPiServer.Commerce.XYZ
{
    public class RegisterRoutingModuleSample : IInitializableModule
    {
        public void Initialize(InitializationEngine context)
        {
            MapRoutes(RouteTable.Routes);
        }
        private static void MapRoutes(RouteCollection routes)
        {
            CatalogRouteHelper.MapDefaultHierarchialRouter(routes, true);
        }
        public void Uninitialize(InitializationEngine context) { /*uninitialize*/}
        public void Preload(string[] parameters) { }
    }
}

EpiServer Commerce specific Attributes

We can use any attribute developed for CMS, in our commerce content type models. e.g.  ContentType attributes, Access attributes, AvailableContentTypes attributes, TemplateDescriptor attribute, Property attributes, Image URL attribute and Default backing types also.

There are only a few specific attributes for commerce only that we can use in our models

CatalogContentType attribute
To connect the content type with an existing meta class, the CatalogContentTypeAttribute can be used. we connect them by defining the name of the meta class that should be connected to the content type.

using EPiServer.Commerce.Catalog.ContentTypes;
using EPiServer.Commerce.Catalog.DataAnnotations;
namespace CodeSamples.EPiServer.Business.Commerce.Catalog.Provider
{
    [CatalogContentType(MetaClassName = “WineSKU”)]
    public class CatalogContentTypeAttributeSample : VariationContent
    {
    }

}

Encrypted attribute
To have “Use Encryption” enabled, we can use Encrypted attribute. It will encrypt the value when storing in MetaData plus.

SaveHistory attribute
To have “Save History” enabled, we can use SaveHistory attribute. This will save history of changes to the value in this property when storing in MetaData plus.

[Searchable(false)]

[CultureSpecific]
[UIHint(UIHint.CatalogContent)]
[Display(
            Name = “Catalog Node”,
            Description = “The catalog node from episerver commerce”,
            GroupName = TabNames.SITE_CONFIGURATION)]

public virtual ContentReference CatalogNode { get; set; }

To get the benefit of catalog browsing intefaces in CMS we can add a property like below in our CMS Page. few other members that can be used for UIHint are as following CatalogEntry, CatalogNode, CurrencySelector, DateTimeRangeSelector, DateTimeSelector, DecimalEditor, EmailAddress, MarketSelector, ProductVariation, SaleCodeEditor and TaxCategorySelector( defined in EPiServer.Commerce).

Strongly Type Models in EPiServer Commerce

We can create Strongly typed models just by inheriting a proper type from EPiServer.Commerce.Catalog.ContentTypes and and decorating it with the ContentTypeAttribute attribute. that means those types will be available as ContentData.

To create models for commerce content following types are available.
VariationContent: A type for variation/SKU models.
ProductContent: A type for product models.
BundleContent: A type for bundle models.
PackageContent: A type for package models.
DynamicPackageContent: A type for dynamic package models.
NodeContent: A type for category/node models.

Examples:

using EPiServer.Commerce.Catalog.ContentTypes;
using EPiServer.Commerce.Catalog.DataAnnotations;
namespace EPiServer.Commerce.XYZ.Models.MetaDataClasses
{
    [CatalogContentType(GUID = “BE40A3E0-49BC-48DD-9C1D-819C2661C9BC”, MetaClassName = “Fashion_Item_Class”)]
    public class FashionItemContent : VariationContent
    {
        public virtual string Description { get; set; }
    }
}
namespace EPiServer.Commerce.XYZ.Models.MetaDataClasses
{
    [CatalogContentType(GUID = “35A29D99-3531-4E4B-A40E-EF262E9DB8B5”, MetaClassName = “FashionStoreLandingNode”)]
    [AvailableContentTypes(Include = new Type[] { typeof(FashionProductContent), typeof(FashionItemContent) })]
    public class FashionStoreLandingNodeContent : NodeContent
    {
        public virtual string Description { get; set; }
    }
}
namespace EPiServer.Commerce.XYZ.Models.MetaDataClasses
{
    /// <summary>
    /// FashionProductContent class, map to Fashion_Product_Class metadata class
    /// </summary>
    [CatalogContentType(GUID = “18EA436F-3B3B-464E-A526-564E9AC454C7”, MetaClassName = “Fashion_Product_Class”)]
    public class FashionProductContent : ProductContent
    {
        public virtual string Description { get; set; }
    }

}
Furthermore EPiServer Commerce provides a content provider that can serve any catalog content as IContent. That means an IContentRepository can be used to work with the content the same way we do in EPiServer CMS. 
public ContentReference CreateNewSku(ContentReference linkToParentNode)
{
    var contentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();
    //Create a new instance of CatalogContentTypeSample that will be a child to the specified parentNode.
    var newSku = contentRepository.GetDefault<CatalogContentTypeSample>(linkToParentNode);
    //Set some required properties.
    newSku.Description = “Great”;
    //Publish the new content and return its ContentReference.
    return contentRepository.Save(newSku, SaveAction.Publish, AccessLevel.NoAccess);
}

Assets and media in EpiServer Commerce 7.5

Asset management in Commerce

By default the new content-based asset management system with the blob provider model  is used for adding assets to the catalog nodes and entries when manging catalogs. All files are stored in the same location as the EPiServer CMS files, providing a more unified user experience.

In a Commerce installation, products and product variants from the product catalog can be accessed from the Catalogs gadget in the Assets pane, with general support for drag and drop of content items into CMS pages and blocks. The integration is done using content type classes EPiServer.Commerce.Catalog,

EPiServer.Commerce.Catalog.ContentTypes and EPiServer.Commerce.Catalog.Provider.
Configuration of asset management systemThe legacy Asset Management system for Commerce Manager is still available in EPiServer Commerce, but by default the new asset management system is configured to be used. A notification message with this information is displayed.
The configuration setting UseLegacyAssetSystem specifies the asset management system to be used, if set to “true” the legacy ECF asset system in Commerce Manager will be used. The setting is configured as follows in the web.config files of both the Commerce Manager and the front-end sites:
 <appSettings>
  <add key=”UseLegacyAssetSystem” value=”” />
  …
</appSettings>

VPP system in Episerver CMS 7.5

The VPP system is no longer used for storing editor generated content, which means that all CMS extensions to the VPP system are being phased out. The VPP API defined in EPiServer Framework will continue to be used for mapping in folders such as add-ons.
By default the new content-based asset management system with the blob provider model is used for adding assets to the catalog nodes and entries when manging catalogs. All files are stored in the same location as the EPiServer CMS files, providing a more unified user experience.

Blob Storage and Blob providers in Episerver CMS 7.5

BLOB (Binary Large Object) providers is a framework designed to store large amounts of binary data in a more optimized and cost-effective solution such as cloud storage, instead of in the database. The EPiServer platform supports BLOB storage of assets using a provider-based setup, and has a built-in file BLOB provider. You have the following options:
Built-in BLOB provider. EPiServer has a built-in BLOB provider for media files such as images, videos and documents. By default this provider will store files on local disc or a file share which will be defined during installation.
Customized BLOB provider. You can also develop and configure your own customized BLOB provider for your specific hosting environment. As an example, an Azure BLOB provider for EPiServer is available via Nuget.

A provider is responsible for storing a stream of data and associate it with a unique identifier. BLOBs are grouped into containers which is a logical name for a set of BLOBs, that for example can be deleted using a single API call. The unique identifier is exposed as an URI in the format epi.fx.blob://[provider]/[container]/[blob]] to make it easy to store a reference to a BLOB in for example a database.
Most methods in the API will always return a reference even though the actual BLOB does not exists, since it would be too costly to go out to a cloud service everytime, for example, a call to GetBlob is made, and it is assumed that the caller keeps track of BLOB identifiers.

Please Note we can’t use Unified File any more to find the physical locations of files, Science have been moved in BLOBFactory classes. There are few example helper functions that you may require in your projects regarding product images.

/// <summary>
/// Get absolute Path Of File
/// </summary>
/// <param name=”assetKey”></param>
/// <returns></returns>
public static string GetAbsolutePath(string assetKey)
{
var contentReference = PermanentLinkUtility.FindContentReference(new Guid(assetKey));
if (contentReference != null)
{
var contentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();
var blobFactory = ServiceLocator.Current.GetInstance<BlobFactory>();
var fileID = new ContentReference(contentReference.ID);
//Get the file
var file = contentRepository.Get<MediaData>(fileID).BinaryData;
return file.ID.AbsolutePath;
}
return string.Empty;
}


private static string GetVirtualPath(string assetKey)
{
    var contentReference = PermanentLinkUtility.FindContentReference(new Guid(assetKey));
    return new UrlResolver().GetVirtualPath(contentReference, “en”);
}
public static string GetAssetUrl(Entry entry)
{
if (entry.Assets != null)
{
var assetKey = entry.Assets.OrderBy(a => a.SortOrder).FirstOrDefault().AssetKey;
return GetVirtualPath(assetKey);
}
return DefaultUrl;
}
public static string GetAssetUrl(CatalogNode node)
{
if (node.Assets != null)
{
var assetKey = node.Assets.OrderBy(a => a.SortOrder).FirstOrDefault().AssetKey;
return GetVirtualPath(assetKey);
}
return DefaultUrl;

}

Installing EpiServer Community on a commerce site

Installing EPiServer relate on an EPiServer CMS 7 site working with EPiServer Commerce can be a challenge, This post can be helpful for those who are trying to do this or facing issue in installing other EPiServer products.

Technologies under discussion are
EPiServer CMS 7.1,
EPiServer Commerce 1 R3
EPiServer Relate+ 7

Issue: Installing Commerce and Relate (Community) is a no go
http://world.episerver.com/Support/Bug-list-beta/bug/95414/


Issue details:
An unhandled error has occured:
 The argument is null or empty. Supply an argument that is not null or empty and
 then try the command again.
When executing
At C:Program Files (x86)EPiServerCommonFramework7.0.844.1InstallSystem Sc
 riptsUpgrade Site.ps1:93 char:17
+ -SqlServerName <<<< $properties.DatabaseServerName `

 An unhandled error has occured:
 The argument is null or empty. Supply an argument that is not null or empty and
 then try the command again.
When executing
At C:Program Files (x86)EPiServerCommonFramework7.0.844.1InstallSystem Sc
 riptsUpgrade Site.ps1:93 char:17
+ -SqlServerName <<<< $properties.DatabaseServerName `
=
Get-EPiIsBulkInstalling
At C:Program Files (x86)EPiServerCommonFramework7.0.844.1InstallSystem ScriptsUpgrade Site.ps1:93 char:17
 + -SqlServerName <<<< $properties.DatabaseServerName `
System.Management.Automation.ParentContainsErrorRecordException: Cannot validate argument on parameter ‘SqlServerName’. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.


Possible Solutions:
Solution 1:
  • Follow process for installing CMS 7, Relate, Commerce
  • Install Site with database, with Commerce and the sample site
  • Install a Relate site and note references. 
  • Add the same references to the Commerce site
  • Copy and paste Community/Mail related sections of web.config in the Relate site to the commerce web.config
  • Find the install database script in the install directory for Relate, run the script against the site database to create the Community tables.
(I will write a separate post that how we can merge a community data base with a CMS database.)

Solution 2: STAR Solution, I tried a different approach that can be used in other setup related issues also. 
  • Find the issue in PS1
  • Fix the issue in PS1 File.
  • Remove the Signature At the bottom of the site. e.g # SIG # Begin signature block …………………………………………… # SIG # End signature block
  • Now File is no longer signed therfore we will need some power shell policy adjustments.
  • PS C:Userstobias> Set-ExecutionPolicy ‘unrestricted’
  • Set-ExecutionPolicy -scope CurrentUser -executionPolicy Unrestricted
  • Re-Run the setup and fix the other Issues.

I tried this approach to solve some issues while installing Commerce on a hosting server also.

Unwanted Lucene Search Results in EpiServer Commerce R2

Issue: User was getting unexpected search results for products, e.g. with a search key word ‘Sate’ he was getting same result as for ‘Site’. Although for most of the clients they will happy with these results but this particular client was unhappy with this result due to their business requirements. We do not have any word like ‘Sate’ in our Database or in Index file for Lucene. Clearly it was Fuzzy search that was causing this although in code we have set FuzzySearch = false;

Reason:
// Perform Lucene search
SearchResults results = searchFilterHelper.SearchEntries(criteria) as SearchResults;
In the Mediachase.Commerce.Website, Version=5.2.243.2, SearchFilterHelper’s SearchEntries() method, below:
public virtual ISearchResults SearchEntries(CatalogEntrySearchCriteria criteria) {  try  {
  _Results = Manager.Search(criteria);
 }
 catch (SystemException)
 {
  if (HttpContext.Current.IsDebuggingEnabled)
   throw;
 }
 // Perform fuzzy search if nothing has been found 
if (_Results.TotalCount == 0)  {
  criteria.IsFuzzySearch = true;
  criteria.FuzzyMinSimilarity = 0.7f;
  _Results = Manager.Search(criteria);
 }
 return _Results;
}
As you can see there is an initial call to Manager.Search().
Before returning, the TotalCount property on the ISearchResults object returned is checked to see if there were no results.
If there are no results a fuzzy search is done.

That was causing the issue although iSFuzzySearch was false at the time of request.

Fix: A fix is present in Episerver Commerce R2 Sp2. There is an extra Function is available that can be used to stop FuzzySearch if no result is found with actual keyword.
public virtual ISearchResults SearchEntries(CatalogEntrySearchCriteria criteria, bool isFuzzySearch, float minSimilarity)
// Perform Lucene search
SearchResults results = searchFilterHelper.SearchEntries(criteria,false,0) as SearchResults;

Special thanks to Jeff from EpiServer’s Developer Support team to find out the reason and fix.

Example Code:
internal CatalogIndexSearchDataSource CreateDataSource(SearchFilterHelper filter, int pageNo, int pageSize, ref int totalRows, bool cacheResults, int cacheTime, string nodeString, string keywords, List<string> metaClasses)
        {
            var currentCulture = Thread.CurrentThread.CurrentUICulture;
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(SiteContext.Current.LanguageName);
            var recordsToRetrieve = pageSize;
            //cache timeout
            TimeSpan cacheTimeout = new TimeSpan(0, (int)cacheTime, 0);
            // Perform search
            SearchSort sortObject = null;
            // Put default sort order if none is set
            if (sortObject == null)
                sortObject = CatalogEntrySearchCriteria.DefaultSortOrder;
            var criteria = filter.CreateSearchCriteria(keywords, sortObject);
            //If meta classes are given to search.
            if (metaClasses != null)
                foreach (string metaClass in metaClasses)
                    criteria.SearchIndex.Add(metaClass);
           
            //Add catalogs
            foreach (var row in CatalogContext.Current.GetCatalogDto(SiteContext.Current.SiteId).Catalog)
            {
                if (row.IsActive && row.StartDate <= FrameworkContext.Current.CurrentDateTime && row.EndDate >= FrameworkContext.Current.CurrentDateTime)
                    criteria.CatalogNames.Add(row.Name);
            }
            //add catalog nodes
            if (!string.IsNullOrEmpty(nodeString))
            {
                foreach (string outline in SearchFilterHelper.GetOutlinesForNode(nodeString))
                {
                    criteria.Outlines.Add(outline);
                }               
            }
            CatalogIndexSearchDataSource dataSource = null;
            // No need to perform search if no catalogs specified
            if (criteria.CatalogNames.Count != 0)
            {
                Entries entries = new Entries();
            // Perform Lucene search
            SearchResults results = searchFilterHelper.SearchEntries(criteria,false,0) as SearchResults;
           
            // Get IDs we need
            int[] resultIndexes = results.GetIntResults(pageNumber , maxRows+5); // we add padding here to accomodate entries that might have been deleted since last indexing
            if (resultIndexes.Length > 0)
            {
                int[] productResultIndexes = RefinementHelper.GetParentProducts(pageSize, pageNumber, resultIndexes, ref totalRows);
                // Retrieve actual entry objects, with no caching
                entries = CatalogContext.Current.GetCatalogEntries(productResultIndexes, false, new TimeSpan(), responseGroup);
                // Add in attribute information
                AddAttributes(entries, results);
                // Insert to the cache collection
                entries.TotalResults = totalRows;
                CatalogCache.Insert(cacheKey, entries, cacheTimeout);                dataSource = new CatalogIndexSearchDataSource { TotalResults = totalRows, CatalogEntries = entries };
            }
            Thread.CurrentThread.CurrentUICulture = currentCulture;
            return dataSource;
        }

Clone a purchase order and convert into cart

We have a requirement for our client that he can masquerade user and can create a new cart based on some existing Purchase Order(e.g. for damaged/lost orders).

Option 1: Get The OrderForm and other objects from PurchaseOrder and assign it to new Cart.
It did not work as result was a nasty output. On saving Purchase Order for new cart, OrderForm from Parent was assigned to new cart and parent Purchase order lost its associated OrderForms.

Option 2:
Clone the Purchase Order and create a cart based on that but it will not work because. (I tested this with EpiServer Commerce R2SP2)
Type ‘Mediachase.Commerce.Orders.PurchaseOrder‘ in Assembly ‘Mediachase.Commerce, Version=5.2.628.0, Culture=neutral, PublicKeyToken=6e58b501b34abce3’ is not marked as serializable.
Solution:
We can clone OrderForms and OrderAddresses. Therefore I created a clone copy of OrderForm and order addresses and added that into the Cart.
Below piece of code helped me to achieve this. Note I have not tested/run workflows.
Cart mycart = OrderContext.Current.GetCart(“replacementcart”, SecurityContext.Current.CurrentUserId);
                CopyCart(mycart, Order);
//Delete and added a new Payment(Zero Charged)
//Convert into Purchase Order

        /// <summary>
        /// Copy cart
        /// </summary>
        /// <param name=”_cart”></param>
        /// <param name=”orderGroup”></param>
        public static void CopyCart(Cart _cart, PurchaseOrder orderGroup)
        {
            // Initial validation
            if (_cart == null) throw new ArgumentNullException(“_cart”);
            if (orderGroup == null) throw new ArgumentNullException(“orderGroup”);
            // need to set meta data context before cloning
            MetaDataContext.DefaultCurrent = OrderContext.MetaDataContext;
            OrderForm of = orderGroup.OrderForms[0].Clone() as OrderForm;
           
            // Remove existing Order Forms
            for (int i = _cart.OrderForms.Count-1 ; i>=0;i–)
            {
                _cart.OrderForms[i].Delete();
            }
            //Add order Forms to basket from PurchasOrder.
            _cart.OrderForms.Add(of);
            // Remove existing Order Addresses
            for (int i = _cart.OrderAddresses.Count-1 ; i>=0;i–)
            {
                _cart.OrderAddresses[i].Delete();
            }
            foreach (OrderAddress address in orderGroup.OrderAddresses)
            {
                MetaDataContext.DefaultCurrent = OrderContext.MetaDataContext;
                OrderAddress oa = address.Clone() as OrderAddress;
                _cart.OrderAddresses.Add(oa);
            }           
            _cart.SetParent(_cart);
            _cart.AddressId = orderGroup.AddressId;
            _cart.AffiliateId = orderGroup.AffiliateId;
            _cart.ApplicationId = orderGroup.ApplicationId;
            _cart.BillingCurrency = orderGroup.BillingCurrency;
            _cart.CustomerId = orderGroup.CustomerId;
            _cart.CustomerName = orderGroup.CustomerName;
            _cart.ProviderId = orderGroup.ProviderId;
            _cart.Status = orderGroup.Status;
            _cart.Owner = orderGroup.Owner;
            _cart.OwnerOrg = orderGroup.OwnerOrg;
            _cart.ShippingTotal = orderGroup.ShippingTotal;
            _cart.SiteId = orderGroup.SiteId;
            _cart.SubTotal = orderGroup.SubTotal;
            _cart.TaxTotal = orderGroup.TaxTotal;
            _cart.Total = orderGroup.Total;
          
            _cart.AcceptChanges();
        }

Get the CatalogNode of Product Listing Page

 

There are some instances when we need to know the Parent nodes of a Page based on [catalogue] Product Listing. E.g. I have a scenario when we are setting up header menus for products. Editor can select a parent Node for display child nodes as menus. But episerver classes doesnot provide any public function to return the CatalogNode of an active Product listing page. Following piece of code can help us in these scenarios.
private stringnodeName = string.Empty;
//Is it a category listing Page
bool isCatalogNodePage = BreadcrumbsFactory.IsCatalogNodePage(CurrentPage);
//Is it a product listing page
bool isProductPage = BreadcrumbsFactory.IsProductPage(CurrentPage);
           
//Get the parent catalog node/s of this page.
if (isCatalogNodePage)
{
CatalogNode node = CurrentPage.GetParentCatalogNodeCode();
       if (node != null)
              nodeName = node.ID;
       }
       else if(isProductPage)
       {
              CatalogNode node = CurrentPage.GetParentCatalogNodeCode();
              do
              {
              if(node != null)
              {
                     if (string.IsNullOrEmpty(nodeName))
                     nodeName = node.ID;
                     else
nodeName = string.Format(“{0}|{1}”, nodeName, node.ID);
node = CatalogContext.Current.GetCatalogNode(node.ParentNodeId);
              }
              } while(node.ParentNodeId>0);
}
/// <summary>
        /// Get CatalogNode of this page
        /// </summary>
        /// <param name=”page”></param>
        /// <returns></returns>
        privatestatic CatalogNode GetParentCatalogNodeCode(this PageData page)
        {
            if(BreadcrumbsFactory.IsProductPage(page))
            {
                stringtext = page[“ec”] as string;
                if(!string.IsNullOrEmpty(text))
                {
                    EntrycatalogEntry = CatalogContext.Current.GetCatalogEntry(text);
                    CatalogRelationDtocatalogRelationDto = CatalogContext.Current.GetCatalogRelationDto(0, 0, catalogEntry.CatalogEntryId, string.Empty, new CatalogRelationResponseGroup(CatalogRelationResponseGroup.ResponseGroup.NodeEntry));
                    if(catalogRelationDto.NodeEntryRelation.Count > 0)
                    {
                        int catalogNodeId = catalogRelationDto.NodeEntryRelation[0].CatalogNodeId;
                        returnCatalogContext.Current.GetCatalogNode(catalogNodeId);
                    }
                }
            }
            else
            {
                if(BreadcrumbsFactory.IsCatalogNodePage(page))
                {
                    stringtext2 = page[“CatalogNode”] as string;
                    if(!string.IsNullOrEmpty(text2))
                    {
                        CatalogNode catalogNode = CatalogContext.Current.GetCatalogNode(text2);
                        return CatalogContext.Current.GetCatalogNode(catalogNode.ParentNodeId);
                    }
                }
            }
            returnnull;
        }