Archive for March 2010
One of collage was facing issue when he tries to get Advertisement content selector. On below code he used to get the error.
| ContentSelector adcontent = CommerceContext.Current.TargetingSystem.SelectionContexts["advertising"].GetSelector(); |
He was new to commerce server and he was getting System.NullReferenceException as shown below.
You will get such errors if targeting context details are not properly configured in web.config. Couple of checks you can make.
1. Make sure CommerceServerSelectionModule exist in <httpModules>
|
<add name="CommerceContentSelection" type="Microsoft.CommerceServer.Runtime.Targeting.CommerceContentSelectionModule, Microsoft.CommerceServer.Runtime, Version=6.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> |
2. Make sure Advertisement entry is properly configured in contentselection settings
|
<contentSelection> <add name="Advertising" cacheName="Advertising" selectionPipeline="advertising" eventPipeline="recordevent" redirectUrl="./redir.aspx"/> </contentSelection> |
After performing both changes, we are able to get the advertisement content selector.
If you like this post, please click on our sponsor advertisement.
With the introduction of multi-channel, we are able to inject the functionality easily into the application through channel configuration. That means the broker controls the execution of the operations through the Microsoft Multi-Channel Commerce Foundation operation sequence. In some instances, we need to know what data exists in request and response object and there is no such mechanism OOB with commerce server 2009 to see the object’s data (like health monitoring system in BizTalk). To address this problem, I come up with small component which will log the object (context, request and response) information into text file.
Note: This is costly operation (creating text file per request) and request not to use it in production system.
Here are the steps we should follow to create logging component.
- Create a class project – CS2009ObjectLogger and sign the assembly with a key.
- Add a new class name CS2009RequestLogger.cs
- Copy below code in CS file.
// This code is created by Ravi Kanth Koppala and the developer
// can use this code as it is or tweak the code to address
// the requirement. The author will not support the code.
// Copyright 2010 – CommerceServerGuru.comusing System;
using System.Collections.Generic;
using Microsoft.Commerce.Contracts.Messages;
using Microsoft.Commerce.Broker;
using Microsoft.Commerce.Providers.Components;
using System.Xml.Serialization;namespace CommerceServerGuru.Tools.Loggers
{
public class CS2009RequestLogger : OperationSequenceComponent
{const string CRLF = "\r\n";
static Dictionary<string, CommerceQueryOperationResponse> previousResponses = new Dictionary<string, CommerceQueryOperationResponse>();
/// <summary>
/// Handles the Query operation for Marketing Templates
/// </summary>
/// <param name="queryOperation">Operation to process</param>
/// <param name="operationCache">Request-level cache</param>
/// <param name="response">Response for the operation</param>
public override void ExecuteQuery(
CommerceQueryOperation queryOperation,
OperationCacheDictionary operationCache,
CommerceQueryOperationResponse response)
{CommerceRequestContext commerceRequestContext
= OperationContext.CurrentInstance.RequestContext;var encoding = new System.Text.ASCIIEncoding();
var myStream = new System.IO.FileStream(@"C:\inetpub\wwwroot\wss\VirtualDirectories\1234\bin\Requests_" + commerceRequestContext.RequestId + ".xml", System.IO.FileMode.Append);var extraTypes = new Type[3];
extraTypes[0] = typeof(Microsoft.Commerce.Contracts.CommerceRelationshipList);
extraTypes[1] = typeof(CommerceQueryRelatedItem);
extraTypes[2] = typeof(CommerceModelSearch);String rawXml =
@"<CommerceRequest><Channel>{0}</Channel><RequestId>{1}</RequestId><UserId>{2}</UserId><UserLocale>{3}</UserLocale><UserUILocale>4</UserUILocale><CommerceRequest>";
string processXML = string.Format(rawXml,
commerceRequestContext.Channel,
commerceRequestContext.RequestId,
commerceRequestContext.UserId,
commerceRequestContext.UserLocale,
commerceRequestContext.UserUILocale
);
// Note: You may get following error when you try to serialize CommerceRequestContext.
// System.InvalidOperationException: The type Microsoft.Commerce.Portal.Common.Contracts.Messages.CommerceRequestContext was not expected.
// Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
try
{
if (!previousResponses.ContainsKey(commerceRequestContext.RequestId))
{
byte[] exBytes = encoding.GetBytes(processXML);
myStream.Write(exBytes,0, exBytes.Length);
}
}
catch (Exception ex)
{
WriteStringToStream(ex.ToString(), myStream);
}myStream.Write(encoding.GetBytes(CRLF), 0, encoding.GetBytes(CRLF).Length);
var mySerializer = new XmlSerializer(typeof(CommerceQueryOperation), extraTypes);
try
{
if (!previousResponses.ContainsKey(commerceRequestContext.RequestId))
{
mySerializer.Serialize(myStream, queryOperation);
}
}
catch (Exception ex)
{
WriteStringToStream(ex.ToString(), myStream);
}myStream.Write(encoding.GetBytes(CRLF), 0, encoding.GetBytes(CRLF).Length);
var mySerializerResponse = new XmlSerializer(typeof(CommerceQueryOperationResponse), extraTypes);
try
{
mySerializerResponse.Serialize(myStream, response);
}
catch (Exception ex)
{
WriteStringToStream(ex.ToString(), myStream);
}if (previousResponses.ContainsKey(commerceRequestContext.RequestId))
{
WriteStringToStream("Found Previous Request:" + CRLF, myStream);
mySerializerResponse.Serialize(myStream, previousResponses[commerceRequestContext.RequestId]);
}
else
{
previousResponses.Add(commerceRequestContext.RequestId, response);
}myStream.Write(encoding.GetBytes(CRLF), 0, encoding.GetBytes(CRLF).Length);
myStream.Close();
myStream.Dispose();}
/// <summary>
/// Logs error into the log file.
/// </summary>
/// <param name="myString">Error message to write to log</param>
/// <param name="myStream">File stream</param>
private void WriteStringToStream(string myString, System.IO.FileStream myStream)
{
if (myStream == null) throw new ArgumentNullException("myStream");
var encoding = new System.Text.ASCIIEncoding();
byte[] exBytes = encoding.GetBytes(myString);myStream.Write(exBytes, 0, exBytes.Length);
}}
}
- Note: the file location is hardcoded and if possible you can write the file in common location (c:\windows\temp).
- Build the solution and deploy the tool in GAC.
- The next step is to modify site’s ChannelConfiguration.config file and add the below code wherever you need logging functionality.
| <Component name="CommerceSererGuru Tools – Logging" type="Your Full Class Type, Your Assembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=Your Public Key"/> |
That’s all, now you have completed your operation sequence. If you execute the application, you can able to see xml files (with data) created in the folder. Click below link to download the code.
If you like this post, please click on our sponsor advertisement.
Nice to see old errors back on the screen and we can fix them fast as we already know the remedy. One of my team member was getting “Loading Editor” error on click on site editor or profiles in commerce server manager. She was not able to proceed with her work and the error she is getting is not new to commerce server resources but when we bing/google, you may not find a remedy nor you don’t see any entry in the event log.
Couple of alternative solutions to fix this issue.
1. Uncheck “Enhance security configuration” components under IE. To do this, follow these steps:
1. Click Start, click Settings, click Control Panel, and then double-click Add or Remove Programs.
2. In Add or Remove Programs, click Add/Remove Windows Components.
3. In the Windows Components Wizard, click to select the Internet Explorer Enhanced Security Configuration check box, and then click Details.
4. Click to clear the For administrator groups check box.
5. Click to clear the For all other user groups check box, and then click OK.
6. Click Next, and then click Finish.
2. Add the name of the computer to the trusted sites. To do this, follow these steps:
In Internet Explorer, click the Tools menu, and then click Internet Options.
In the Internet Options dialog box, click the Security tab.
Under Select a Web content zone to specify its security settings, click Trusted sites, and then click Sites.
In the Trusted sites dialog box, type http://<ComputerName>, click Add, and then click OK two times.Note: adding localhost will not fix this issue – you should add computer name.
Once the above changes are done, we are able to see the profiles/site terms. After fixing the issue, I am able to find the same has been documented in support article and the url is http://support.microsoft.com/kb/937764.
If you like this post, please click on our sponsor advertisement.
After installing commerce server 2009, you can able to find commerce SharePoint extensibility kit under commerce server folder. By using this kit, we can able to extend OOB SharePoint website easily. This is a very interesting topic, as we will end up spending a lot of time getting this kit customized/deployed (with lot of troubles). Instead of directly jumping into the code, it’s important to understand the existing architecture and how to get good value we get out of it. Note that no two commerce server implementations are same and developers has to extend or customize commerce server site as well as default website to meet to the requirements. Developers can either extend commerce entity by adding new properties and operation sequences or sometimes we have to call external/internal services to push/pull information or we may need to customize the flow of the website (B2C takes payment on checkout but B2B may take payment after dispatch, etc).
Before we discuss further, let’s check different layers of commerce foundation.
Runtime API is at the bottom of the stack which resides in the Microsoft.CommerceServer namespace. These hasn’t been removed in CS2009, so all of your old CS2007 code will still work in the new system, but I highly recommend to migrate to new CS2009 API when doing new development as new API architecture provides us flexibility to extend the application easily and also allow us to scale out the application easily in production but the only big disadvantage I see is the impact to application performance.
Multi-Channel Commerce Foundation are the set of libraries which encapsulate the CS2007 API allowing us for a consistent programming model across the various functional stacks (IE: profiles works similar to catalog works similar to marketing – before in CS2007, we used to either use runtime API or agent mode or local mode or access to web services). Microsoft owns and maintains this code and this is what you’re encouraged to code against if you’re doing development in CS2009. The API is actually designed to support full XML serialization of all DTOs, so the idea here was to allow CS to exist in an App-Tier independent of what exists on the front end.
Commerce SharePoint Extensibility Kit
This is everything that sits in the Microsoft.Commerce.Portal namespaces—the idea here is to encapsulate the Multi-Channel Commerce Foundation code to accelerate application deployment on SharePoint. Don’t expect Microsoft to fix any of the issue in this code – if you reach them, they will ask tell you to fix it as you have the source code. Microsoft don’t give us much in the way of deployment guidelines on how to get this out in a production environment. If you observe the code, the source code can be refractor for better maintainability (I used resharper tool and able to find issues like unnecessary usage of namespaces, etc). Additionally, you’re not able to deploy the OOB owned WSP and your custom WSP on the same farm without getting all sorts of conflicts around package contents, so you need to pull the old WSP out or rebrand everything in the package to get this working in parallel with the existing extensibility kit. Here are the steps we should follow
1. Signed your CommerceSharePointExtensibilityKit project with new key and change the key where ever applicable in the solution.
2. Rebuilt them to create the .wsp files "MicrosoftCommerceMOSSDefaultSite.wsp","MicrosoftCommerceWSSDefaultSite.wsp" and "MicrosoftCommerceWebParts.wsp"
3. Retracted & delete already installed commerce server solutions .
4. Deploy both "MicrosoftCommerceMOSSDefaultSite.wsp" and "MicrosoftCommerceWebParts.wsp" on sharepoint site.
So, now that you’ve got fair knowledge, what’s the best practice? As a architect/tech lead you should start balance between what functionality you’re getting out of the core package and how much further you need to customize or introduce into your codebase.
Ask to Microsoft: It would be better Microsoft to include few scripts (batch files), which automatically removes existing WSP and installed new WSP files.
I am still learning and I will blogging the same here.. so, keep visiting my blog.
If you like this post, please click on our sponsor advertisement.
Email communication is common feature in any ecommerce application. Email alerts should be sent to users based on user/system actions such as profile creation, profile update, order confirmation and order status change. Generally the email templates are provided by the business and the application has to build the email body based on the template and replacing tokens in the template. In this article, we will leverage commerce server multi-channel foundation (Operation components) to inject this functionality into the application.
First we will need to create a new Class Project for our Operation Sequence Component, add references to the following references (from C:\Program Files\Microsoft Commerce Server 2007\Microsoft Commerce Server 2009\Assemblies directory).
|
Microsoft.Commerce.Application.Common.dll |
Create a class, for my example say NotifyUser
|
public class NotifyUser: OperationSequenceComponent |
Make sure your class inherits from OperationSequenceComponent. Add the following using statements:
|
using Microsoft.Commerce.Contracts.Messages; |
Now, we need to implementing the operations that are relevant for the component by overriding one of the following virtual methods:
ExecuteCreate
ExecuteQuery
ExecuteUpdate
ExecuteDelete
|
public override void ExecuteCreate(CommerceCreateOperation createOperation, OperationCacheDictionary operationCache, CommerceCreateOperationResponse response) { } |
In this example, we are trying to send email on customer registration. The commerce server broker will execute code within this ExecuteCreate method so, we have to keep our email sending logic within this braces as shown below.
|
public void ExecuteCreate (CommerceOperation operation, OperationCacheDictionary operationCache, CommerceOperationResponse response) { string firstName = string.Empty; try try } } |
Note: Make sure you give strong name to the assembly and deploy in GAC and the assumption I am making is that there exist a service which takes responsibility of sending emails.
The next step is to modify site’s ChannelConfiguration.config file. You will need to find the <MessageHandler> block with the sequence that we are looking to update, which is CommerceCreateOperation_UserProfile. You can search on that string. In the existing <OperationSequence> block you need to add the following at the end of the sequence.
|
<Component name="User Account Creation Notification" type="Your Full Class Type, Your Assembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=Your Public Key"/> |
That’s all, now you have completed your operation sequence. You can put these sequences in any order, add and remove them from the channel configuration.
If you are using UPMMembershipProvider, then you will observe a strange behavior that “CommerceCreateOperation_UserProfile” operation sequence is never called. This is because the provider directly puts data into database without routing it through create operation sequence but once the data is saved, commerce server calls “CommerceUpdateOperation_UserProfile” operation sequence. The work around I found is to keep our component in “CommerceUpdateOperation_UserProfile” block and in the update execute method, you will get profile values in Response method – check if created date and Modified date fields are same or having less difference (less than a second) –> if yes, call the email service to send an email.
If you like this post, please click on our sponsor advertisement.
