Tuesday, February 20, 2018

Sitecore Experience Commerce - antiforgery error in API calls

When attempting to run some of the Experience Commerce APIs via Postman, several of the import and add methods would fail with a 500 error. Inside the logs of the commerce authoring site, the following was present:
66 09:46:58 INFO Request starting HTTP/1.1 PUT http://localhost:5000/api/ExportInventorySets application/json 95
66 09:46:58 INFO Successfully validated the token.
66 09:46:58 INFO AuthenticationScheme: "BearerIdentityServerAuthenticationJwt" was successfully authenticated.
66 09:46:58 INFO AuthenticationScheme: "Bearer" was successfully authenticated.
66 09:46:58 INFO Authorization was successful for user: "sitecore\Admin".
66 09:46:58 INFO Executed action "Sitecore.Commerce.Plugin.Inventory.ApiController.ExportInventorySets (Sitecore.Commerce.Plugin.Inventory)" in 0.6932ms
66 09:46:58 ERROR Connection id ""0HLBNQFHRI3GP"", Request id ""0HLBNQFHRI3GP:00000001"": An unhandled exception was thrown by the application.
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The required antiforgery header value "X-XSRF-TOKEN" is not present.
Thanks to the help of Naveed Ahmad in the community slack channel, by editing the AntiForgeryEnabled setting to false in the config.json for the authoring site I was able to call the APIs successfully.

Monday, February 19, 2018

Sitecore Experience Commerce - Extending an inventory item with a plugin

Out of the box, inventory items (otherwise known as a SellableItem) in Sitecore's Experience Commerce provide fields which will cover most eCommerce business requirements. However when a requirement comes up to add additional custom fields, you will need to create a Plugin.

The developer's guide for Experience Commerce 9.0 has a section on creating your first plugin, however sometimes it's easier to understand when given a working example.

Experience Commerce - creating a plugin
Sitecore provides a guide for How to extend Catalog system entities schema in Sitecore Experience Commerce 9.0. I will expand on this to show how to get this example working in your Experience Commerce instance.
  1. Download the Plugin.Sample.Notes.zip example project, which is available on the page above. This is the plugin which adds custom fields to inventory items.
  2. Rename this plugin to fit in with your organisation's naming conventions and modify to the code to meet your requirements. Effectively you replace all instances of Note or Notes and modify the two fields the example adds to meet your requirements (in my case I needed 4 fields).
  3. Extract the commerce SDK to a suitable location (at the time of writing, the version is: Sitecore.Commerce.Engine.SDK.2.0.1922). 
  4. Install the Sitecore.Commerce.Plugin.vsix Visual Studio plugin contained in this folder.
  5. Inside this folder is the Customer.Sample.Solution solution. This contains the commerce engine and a number of sample plugins.
  6. Move your customized Plugin.Sample.Notes project into the src folder (Sitecore.Commerce.Engine.SDK.2.0.1922\src) and then add this project to the solution.
  7. Plugin referenced in the commerce engine
  8. Add this project as a reference to the Sitecore.Commerce.Engine project.
  9. In the Sitecore.Commerce.Engine project, update the config.json values to match that of your commerce sites (authoring, minions, ops and shops). The key values to update are that of: Thumbprint and EnvironmentName.
  10. Ensure the solution builds correctly, you may need the Sitecore Commerce Nugget package source configured: https://sitecore.myget.org/F/sc-commerce-packages/api/v3/index.json
  11. Publish the Sitecore.Commerce.Engine project to your 4 commerce sites (authoring, minions, ops and shops). Of course you should back these up before publishing.
  12. Load up the content editor of your Sitecore instance and click Update Data Templates on the commerce ribbon. 
  13. Sitecore Experience Commerce - Update Data Templates
  14. Now if you open up the inventory manager in the Commerce UI, you are able to view and edit your new custom fields.
Experience Commerce - Extended catalog item
From my experience, any errors during this process often relate to the SLL certificates and their thumbprints.

Sitecore Experience Commerce - Update Data Templates fails

After deploying a custom plugin to extend SellableItem and add my own custom fields, the Update Data Templates method inside the content editor would fail. The Sitecore instance logs showed (key lines shown, some have been removed):
1828 14:12:13 ERROR Authentication Error
Exception: System.Exception
Message: The certificate thumbprint is invalid or missing from your configuration, secure communication with the Commerce Engine is not possible.
1828 14:12:13 ERROR GetList(id='Catalogs',type='Sitecore.Commerce.Plugin.Catalog.Catalog, Sitecore.Commerce.Plugin.Catalog',skip=0,take=1)?$expand=Items($select=Id)
System.Exception: The certificate thumbprint is invalid or missing from your configuration, secure communication with the Commerce Engine is not possible.
I took a look inside the commerce authoring logs (in my case: C:\inetpub\wwwroot\CommerceAuthoring_Sc9\wwwroot\logs) to see if there were any errors in there. The following was present:
18 14:11:06 ERROR ClientCertificateValidationMiddleware: Certificate with thumbprint 803320317DD6250341065603E375906369603AD3 does not have a matching Thumbprint.
Inside the config.json file for this site there was a thumbprint configured which did not match that of the log file above. It turns our that the certificate thumbprint which was configured was that of a different domain (http://MySite instead of http://localhost), changing this certificate configured to that of the log file above (the correct domain matching) allowed the Update Data Templates to complete successfully. 

A handy PowerShell command for tracing a thumbprint to a certificate is as follows:
cd CERT:\\
PS Cert:\> dir -recurse | where {$_.Thumbprint -eq "D4FC5CC9E022C0CFFF24186BE75DA9EC66DAD1C2"} | Format-List -property *
This helped me figure out an incorrect certificate was configured for my four commerce service sites.

Thursday, February 15, 2018

Sitecore 8.2 submit a WFFM form programatically

WFFM in Sitecore is great for allowing content authors to create and manage forms with a wide array of fields and save actions. It's of course possible to extend the module in many ways (custom validators, fields, save actions and so on). But one area where it lacks is on the user experience on the front end. Hence comes the requirement to submit a form programatically, which not only uses the save actions and fields the author created but also hooks into the reporting.

This simple example below, is a condensed example which shows the submission of a form with a single field called Email. Essentially we get the actual form item to have access to it's fields and save actions. This is then used to create the parameters required to submit the form.
var myEmail = "ryan.bailey@email.com";
Sitecore.Forms.Core.Data.FormItem formItem = Sitecore.Forms.Core.Data.FormItem.GetForm(ID.Parse("{7D47FECC-25DF-4561-A911-683F4F164FA7}")); // Get the form item
var emailField = formItem.Fields.Where(x => x.DisplayName == "Email").FirstOrDefault(); // Get a given field - should null check of course

var controlResults = new List<ControlResult>();
controlResults.Add(new ControlResult(emailField.ID.ToString(), emailField.Name, myEmail ,emailField.Parameters,false));

// Parse save actions
var saveActionXml = formItem.SaveActions;
var actionList = Sitecore.Form.Core.ContentEditor.Data.ListDefinition.Parse(saveActionXml);
var actionDefinitions = new List<ActionDefinition>();
actionDefinitions.AddRange(actionList.Groups.SelectMany(x => x.ListItems).Select(li => new ActionDefinition(li.ItemID, li.Parameters) { UniqueKey = li.Unicid }));

Sitecore.Forms.Core.Handlers.FormDataHandler handler = Sitecore.WFFM.Abstractions.Dependencies.DependenciesManager.Resolve<Sitecore.Forms.Core.Handlers.FormDataHandler>();
handler.ProcessForm(ID.Parse("{7D47FECC-25DF-4561-A911-683F4F164FA7}"), controlResults.ToArray(), actionDefinitions.ToArray()); // Submit form
There are older examples available online, but this one works for me on 8.2 and the reporting is there as well.

Sitecore WFFM programmatic submission does not have data in form reports

I had an instance where I needed to submit a WFFM form (Sitecore 8.2) programatically (as we had user experience requirements that needed it sent via a service call). The form was successfully submitting and in the detailed reports showed this fact:

WFFM detailed reports
However the summary report was empty (as in no graph showing the fields where data was submitted):

WFFM summary report empty
The data export was also showing missing data:

WFFM empty form export
After downloading the export in XML instead of a CSV file, I notice that the field nodes in the XML were showing empty IDs (GUIDs), which meant the fields had not been mapped correctly:

WFFM XML export - empty field IDs
The error was due to the way that I was building up the fields list in the programmatic submission. This was an array of ControlResult objects which represented the form fields. I was originally instantiating the object using the following overload:
public ControlResult(string fieldName, object value, string parameters);
However once I started using the overload that took in field ID, everything started working as expected:
public ControlResult(string fieldId, string fieldName, object value, string parameters, bool secure = false);
Please also see my full example of programmatic submission of WFFM forms in Sitecore 8.2.