Quantcast
Channel: Ryan Bailey Development
Viewing all 287 articles
Browse latest View live

Sitecore custom button on the experience editor ribbon

$
0
0
Many content editors have a preference for using the experience editor (or page editor) to edit the Sitecore content. Much like the content editor it is possible to add your own buttons to the ribbon at the top, it's just done in a different way. In this example I am working with Sitecore 8.

Creating the button

  1. Open up the Sitecore desktop and load the content editor with the core database selected
  2. Navigate to "/sitecore/content/Applications/WebEdit/Ribbons/WebEdit/Page Editor" - it may have a display name of experience editor
  3. In my case I want the button to appear in the edit section, so under Edit I insert a large button (/sitecore/templates/System/Ribbon/Large Button)
    1. The Header field is required and contains the text that will display for the button
    2. The Icon field is required and will be the actual button
    3. The ID field is required and should be a unique id for the button

Creating the code

Firstly we need to create the code that will be run on the button click, this is a c# class.

namespace MyProject.Commands
{
public class MyCommand : PipelineProcessorRequest<ItemContext>
{
public override PipelineProcessorResponseValue ProcessRequest()
{
Item item = base.RequestContext.Item; // The item being edited

// Do code

return new PipelineProcessorResponseValue
{
Value = "Return Value" // Return an object here on value
};
}
}
}

Then we need to register this inside App_Config/Include/Sitecore.ExperienceEditor.Speak.Requests.config.
<request name="ExperienceEditor.MyCommand" type="MyProject.Commands.MyCommand, MyProject"/>

Now inside Website\sitecore\shell\client\Sitecore\ExperienceEditor\Commands we create a JavaScript file MyCommand.js. This is the code which the button click will call.
define(["sitecore"], function(Sitecore) {
Sitecore.Commands.MyCommand = {
canExecute: function(context) {
// Determines whether command is disabled or enabled.
return true;
},
execute: function(context) {
Sitecore.ExperienceEditor.PipelinesUtil.generateRequestProcessor("ExperienceEditor.MyCommand", function(response) {
// response.responseValue.value is the value passed back from the code
}).execute(context);
}
};
});
The above JavaScript method uses canExecute to decide if the button is available for the given context/item and execute to run once the button is clicked.

Connecting the button

  1. Open up Sitecore rocks and locate the button just created (remembering it's in the core database)
  2. Right click the item and select Tasks > Design Layout


  3. Add a rendering and select Large Button


  4. Double click the newly added rendering to edit it's properties
    1. Id is required and should be a unique value (and different from the previous step)
    2. Click is required and should be set to "trigger:button:click"
    3. Command is required and should be the name of the command created earlier (MyCommand)
    4. PageCodeScriptFile is required and should be the location of the JavaScript file created earlier (/sitecore/shell/client/Sitecore/ExperienceEditor/Commands/MyCommand.js)

The button should now appear on the experience editor and run as expected! Remember you can secure the button via the item created in the core database if required.

Setting a Sitecore password policy and protecting from brute force attacks

$
0
0
You might notice that out of the box Sitecore has no real password policy - take the default password for admin, a single character "b". This is not ideal and a security audit will often bring up this fact. On top of a secure password policy is the amount of times that a user can attempt to log in (with an incorrect password) before they are locked out.

By default, the web.config of your Sitecore website will have the following section:
<add name="sql" type="System.Web.Security.SqlMembershipProvider" connectionStringName="core" applicationName="sitecore" minRequiredPasswordLength="1" minRequiredNonalphanumericCharacters="0" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="256" />
The key attributes are:
  1. minRequiredPasswordLength - the minimum length that a password can be. By default this is 1 and is recommended to be changed to 8 or greater.
  2. minRequiredNonalphanumericCharacters - is the minimum required non alphabetic or numeric characters (such as @ or $). By default this is 0, and to enhance password security it should be set to at least 1.
  3. maxInvalidPasswordAttempts - is the number of failed logins a given user account can have before it is locked. By default it is set to 256, which is rather high and could allow for brute force access to an account. This should be changed to a much lower number, such as 10.
Remember as with any password policy it's important to communicate with users and have policies in place for unlocking accounts that breach the maximum invalid login attempts. 

The new Sitecore standard - Helix principals

$
0
0
As a consultant working with Sitecore for a number of years I have had the pleasure to be involved with a large number of Sitecore implementations. These ranged from complete end-to-end implementation to reviews of existing sites. This has allowed me to see Sitecore development principals from a large amount of developers across multiple countries. One surprising aspect of this is the true extent that developers have implemented Sitecore, and whilst it's often pretty good, there are plenty of live examples of John West's Sitecore worst practices.

Luckily Sitecore has recently released the Helix principals which provide: "A set of overall design principles and conventions for Sitecore development". Whilst this has also been released in tandem with the habitat Sitecore project example (which I was lucky enough to be on a team which released one if the first production examples), the topic of this blog post will be primarily on Helix.

So why follow Helix principals?

Well I think Sitecore puts it best on the Helix site itself:
Helix provide a set of guidelines for your Sitecore projects. The Habitat example provides you with a pre-built and tested set of common modules that you can use as an inspiration to your project. Both improve the efficiency of your projects, reduce costs and time to market. As more and more people and organisations adopt the Helix conventions and principles, it will become a Sitecore standard. This means that people who are familiar with the conventions or the Habitat example will be able to work more easily on other convention-based projects with minimal training. It will be easier for Sitecore Product Support to understand projects built using the conventions, enabling them to resolve issues more quickly.
Some of the key take-aways for me are around the project efficiency, setting a global Sitecore standard and of course allowing official support to better understand your project.

What does it cover?

Rather than me rewriting the documentation in a blog format, lets cover off the main areas covered in Helix.

Patterns, Principles and Conventions
  • Architecture Principles: Looks at a modular solution architecturally.
  • Visual Studio: How to setup and structure and Visual Studio solution with projects.
  • File and Disk Structure: The physical structure of solutions and modules.
  • Managing Sitecore Items: Covers managing items in development and deploying them.
  • Templates: The setup of templates and how to reference them in code.
  • Page Layout: A look at page layouts, renderings, data sources and of course placeholders.
  • Configuration and Settings: Strategies for configuration and how to work with Sitecore configuration files.
  • Multi-site and multi-tenant: How to create multi site or tenant (logical grouping such as business unit).
  • Language and culture support: Multi-language implementations of Sitecore and use of Dictionaries.
  • Security and workflows: How to handle permissions in Sitecore and workflows for content editors.
  • Working with code: Code formatting for Sitecore.
  • Visual Design and Theming: A look at the front-end stack for your Sitecore site.
DevOps and development lifecycle management
  • Development: Covers general development and version control.
  • Build and integration: Covers build options for Sitecore projects along with integration points.
  • Testing: Covers managing your tests, along with unit testing and other testing activities (acceptance testing for example).
  • Deployment: Deployment strategy for Sitecore and what should be deployed where.

Get started!

For those users with large existing implementations, this can seem like a daunting list of changes to make your Sitecore solution standardised. But we all have to start somewhere, so I recommend taking one piece at a time. Fixing up how you deal with configuration can make upgrades easier so is a good start. As is the testing and deployment to ensure you have control and quality for what is released into each environment.

For the lucky ones who are starting a clean Sitecore solution, you have the option of taking the Habitat solution and using it outright (or as a best practice example). Or as intended you can take the Helix principals and bring them into your development team as general rules/guiding principals.

Wherever you are at with your particular Sitecore solution, lets all get on board with Habitat and ensure that moving forward we are all producing quality Sitecore sites that are efficient, easy to maintain and best practice!

Sitecore Lucene appending pipe character to field

$
0
0
While implementing blog functionality in Sitecore, using Lucene as a datasource, I noticed that when I output the title field onto the page, it was appending a piped character ("|") to the end.


This wasn't a front-end issue where a | was being output in the repeater, so I used Luke to open the physical search index to see what was actually being stored.


As it turns out there were two fields on the blog post template which had the name title. The second title field was empty which made the pipe character appear to be appended. The truth was that Lucene uses the pipe character to concatenate all data for fields of the same name.

Improving and optimising the performance of your Sitecore website

$
0
0
Statistics around user behavior and page load times is a good bit of background reading on how users perceive the performance of a web site. The standout pieces of information for me was that:
"A 1 second delay in page response can result in a 7% reduction in conversions."
 Along with:
"40% of people abandon a website that takes more than 3 seconds to load."
This then sets the scene for why optimisation of a Sitecore website might be important to the end-users. For Sitecore websites which have a sales/lead generation component, there will be less conversions if the performance is not optimised.

Optimise the front-end

The first thing I always do is take a look at the website using the YSlow tool. This is a browser extension that essentially gives a rating on how well a given page will perform. They key areas it looks at is around the number of HTTP requests, CDN, compression, location of JavaScript/CSS (page blocking), minification and so on. It's a great starting point to get Sitecore optimised and often makes one of the biggest differences to end users.


The main outputs after using this tool should be:

  • CSS/JS bundled and minimised where possible
  • Any third party fonts or JavaScript libraries (jQuery) using CDN where possible
  • Images optimised in terms of size and kept minimal (use sprites in your CSS for example)
  • Static and dynamic compression enabled (this makes a big difference with those JS libraries)
  • Keep the HTTP requests to a minimum, once under load these exponentially affect performance

Optimising the caches


Database caches: Inside Sitecore.config (or web.config) will be a database section for Master, Core and Web. These caches are used to store data coming from the SQL databases and will lead to less database calls and ultimately better performance. The default values are generally not enough for smaller Sitecore implementations and should be optimised in a testing environment for every Sitecore website you work on. The http://server/sitecore/admin/cache.aspx page can be used to monitor these caches and in turn work out the ideal values they should be set to. There are plenty of blog posts/guides on correctly configuring these cache values.


Prefetch caches: When Sitecore is starting up, one of the tasks is to prefetch some data from the various databases, ready to use. These caches are configured in the files available in Website\App_Config\Prefetch and by default will hit key templates, items and item children. Recently I discovered that for the web prefetch cache, Sitecore attempts to cache the default home item and it's children. As many implementations use a custom home item, this is an example of a cache configuration which could be changed. This cache will have a minor impact on startup time, which should be okay on production environments, but will affect developers on their environments.

HTML Output cache: When you use caching for sublayouts/renderings, this data is stored in the HTML output cache. On the Site element for your web site (found under <configuration><sitecore><sites>) there is a variable called htmlCacheSize which controls the size of this cache. By using the cache administration page mentioned above, you are able to see if this cache is adequately sized. Remember to check this page on content delivery servers in a scaled environment, as these are the ones mainly serving data from this cache.

Optimising the database

SQL Server Index Fragmentation: For existing Sitecore implementations which have been active for some time, one area to investigate is the fragmentation percentage of SQL Server. As Sitecore puts it:
As indexes age, insertion and deletion of noncontiguous data can take its toll and cause fragmentation to occur. This can happen in just a few days on a busy CMS database. Minor amounts of fragmentation won't generally hurt performance. But as the percentage of fragmentation increases, performance suffers dramatically.
Your SQL Server database administrator should be able to help run the Index Physical Statistics report, which will then show which indexes have a high percentage of fragmentation  (over 10% is bad). The defragment indexes maintenance plan being run will solve these issues but ensure to make backups beforehand.

Further reading

These are some of the key areas in which I focus on and have found to provide the most benefit to optimising the performance of a Sitecore website. Of course this assumes that the custom code used on the website itself is optimised and running well. 

Introducing the Data Exchange Framework for Sitecore

$
0
0
Some Sitecore implementations can have a requirement to integrate with other third party systems. A common example of this might be a CRM which would sync data to/from Sitecore experience database (contacts). Other examples might be the syncing of product data into Sitecore commerce or simply creating/updating Sitecore items based on a legacy system.

For those of us who have implemented or inherited such integrations in the past, the common problem was often around no real structure and possibility of error. Thankfully Sitecore have released the Data Exchange Framework.

What is the Data Exchange Framework?

To put it simply, it's a framework which handles the transfer of data between two systems. Commonly Sitecore would be one of the two systems (either the source or target). However it is possible to use the framework to handle data exchange between two independent systems - a case for this might be syncing data between a finance system and training management application.

Full documentation for the Data Exchange Framework is available on the Sitecore website - and this is a great example of the new documentation format Sitecore will be using moving forward.

What are it's uses?

Well, the great thing about it being a framework is that the potential uses are really open to your business requirements. Some potential examples I have done in the past whilst working on Sitecore projects, that would be cases for using the Data Exchange Framework are:

  1. Sync course/enrollment data from a training management system. The Sitecore website could then handle new enrollments, existing enrollments and even personalisation based on your course history.
  2. Syncing sales data from Sitecore to a finance system. 
  3. Syncing contact history (products current subscribed to and claims history) from a legacy internal system.
An actual example currently available from Sitecore that uses the Data Exchange Framework is the Dynamics CRM Connect module. The following image is an example of the pipelines (units of work) which this module can perform.


Being that CRM focuses around customers (aka contacts in Sitecore), you will notice that a lot of these pipelines revolve around contacts in the xDb. Other implementations of the Data Exchange Framework might revolve around item creation or update for example.

How does it work?

Without going into too much detail here, the basic gist of the Data Exchange Framework is as follows.

Pipelines are units of work that are performed and are usually related to data transfer. These pipelines can contain multiple Pipeline Steps, which are a series of tasks run in a given order. A Pipeline Processor runs the given pipeline by; deciding which steps to run, running these steps and handling errors. Each pipeline step can also have a Pipeline Step Processor which is the logic used to run that step. The pipeline step might be though of as the configuration (such as the connection string for a CRM), where the pipeline step processor then uses that configuration (step) to actually read/write data in the CRM. There is also a Pipeline Context which allows for data to be shared across multiple pipeline steps in a given pipeline.

Pipelines are run via a Pipeline Batch - which can contain one or multiple pipelines to be run. This wrapper maintains logs of the pipelines running (and when) and can be called via the content editor or as a scheduled job. Of course this then means that there is a Pipeline Batch Processor which handles the logic of which pipelines to run, actually running them and handling any errors.

Going back to my example of Syncing sales data from Sitecore to a finance system, there would likely be the following structure:
  • Update financial system (pipeline)
    • Read data items from Sitecore (pipeline step)
    • Loop through items (pipeline step)
    • Update target system (pipeline step)
This would all then be kicked off via a pipeline batch called sync financial data, which would be run on a schedule (every 30 minutes for example).

Getting started

It all sounds rather complex and may come off as gibberish, however the best advice I can give is to take a read through the Data Exchange Framework documentation. Then actually install the module into a clean Sitecore development environment, along with Sitecore's Dynamics CRM Connect module. The CRM connect module provides a good working example which can help one to grasp the concepts of the framework and provide background for implementing it yourself.

Sitecore Authentication on CES Discovery service failed

$
0
0
Any good Sitecore developer periodically checks their production logs for any error messages or worrying warnings. Whilst doing this on an 8.2 implementation, I noticed the following warning:
ManagedPoolThread #3 09:15:45 WARN Authentication on CES Discovery service failed.
Exception: System.Net.WebException
Message: The remote server returned an error: (403) Forbidden.
Source: System
at System.Net.HttpWebRequest.GetResponse()
at Sitecore.CES.Client.WebClient.ExecuteRequest(String requestUri)
at Sitecore.CES.Client.ResourceConnector`1.Request(String endpoint, Object[] parameters)
at Sitecore.CES.Discovery.EndpointSource.GetEndpoint(String serviceName)
The line before this in the logs states:
INFO  Job started: Update device detection DB
Which  traces back to device detection in Sitecore which is a paid service (since Sitecore 8.1). This can be disabled by using the following patch file:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<settings>
<setting name="DeviceDetection.Enabled">
<patch:attribute name="value">false</patch:attribute>
</setting>
</settings>
</sitecore>
</configuration>
It will then begin to insert the following (more graceful) warning :)
WARN  Device detection component is disabled
For those users who want to use this service, remember to enable the connections to discovery-ces.cloud.sitecore.net and devicedetection-ces.cloud.sitecore.net on the firewall.

The Sitecore Publishing Service

$
0
0
The Sitecore Publishing Service is a new module released for Sitecore 8.2 which provides a stand alone publishing service for larger implementations. Where it excels is with large volume publishing jobs (think older Sitecore web sites with thousands of items) and it's built with the .NET core!

The end result is replacement of the out-of-box publishing feature in Sitecore, which delivers the following key benefits:
  • High performing - faster publishing.
  • More reliable publishing with better data consistency.
  • A better user experience with more feedback via the Publishing Dashboard.
  • Is run as a separate instance to the content management server - could even be on it's own server.
  • Makes use of it's own architecture rather than existing publishing pipelines, setting and features.
  • Installation is done via the publishing service instance and the integrated module on the Sitecore instance.
So what are the key concepts of the Sitecore Publishing Service?
  • Publishing job: A request of item(s) to be published - can be viewed on the publishing dashboard.
  • Manifests: The tasks to be run for a given publishing job. The service uses logic to work out item deletions, related items to be published and so on. A single publishing job can have multiple manifests.
  • Promotion: The act of moving items (data) from the source (generally the master database) to the target (generally the web database) by following the manifest(s).
  • Manifest results: A list of all changes that were made for a given publishing job. This can be accessed via pipelines for customization.
The steps that the publishing service takes are as follows:
  1. Publishing quests are queued - and then executed.
  2. Connect directly to the SQL Server source/target databases and process the job.
  3. Issue events - such as a cache clear on content delivery instances.
  4. Report back to the user interface - publishing dashboard.
The flow of a publishing job

Detailed look at the various steps

This is a great new release that shows Sitecore is looking to push forward into the future by building on top of the .NET core. Publishing has been a pain point for a number of years around consistency and my personal pet peeve of accidentally closing the publish window during a job. This module may not interest the smaller Sitecore implementations, but those of you who have to wait an hour for a publish using the classic method (imagine kicking off a full publish by mistake) will really appreciate this one.

Sitecore publishing service is not running error

$
0
0
After spinning up the new Publishing Service for Sitecore 8.2 I noticed that publishing was not working and the following error was appearing on the publishing dashboard.
The publishing service is not running. Please contact your system administrator.


This error is generally caused when Sitecore is unable to connect to the publishing service itself. You should ensure that you can access it in the browser and are able to see "{“status”:0}" - which means it's working okay. Also check the PublishingServiceUrlRoot inside the show config admin page to ensure it points correctly to the service URL.

Sitecore error - Could not get pipeline: speak.client.getStyle

$
0
0
After a deployment on Sitecore version 8.1 the following error was appearing when attempting to load the administration launchpad.
Could not get pipeline: speak.client.getStyle (domain: )
I did a search through a clean Sitecore instance's configuration file and found the reference speak.client.getStyle section in the App_Config/Include/001.Sitecore.Speak.Important.config file.

Loading up the show config administration page on the suspect server, there were no patches from 001.Sitecore.Speak.Important.config and browsing the App_Config folder confirmed this file was disabled. Removing the .disabled file extension solved the issue.

Sitecore package installation never ends

$
0
0
The Sitecore Package Designer is a great way to share content between environments and developers. One annoying error is that on installation of a package it will never end. Upon checking the content structure you will also notice that no content has been installed.


In Sitecore 8+ you will encounter this error if the Sitecore instance is unable to connect to MongoDB. The following will usually be present throughout the logs:
Exception: System.NullReferenceException
Message: Object reference not set to an instance of an object.
Source: Sitecore.Analytics.MongoDB

Simply installing MongoDB and having it running (and configured correctly in the connection strings) will allow the package installer to complete installation as expected.

C# SOAP service call and an empty SOAPAction header

$
0
0
Working with a third party service, one of the methods tested okay when using SoapUI, however whenever called via .NET code it would return a 500 error.

Looking at the WSDL, the method required a soap action of "", literally an empty string. So using fiddler I was able to see the request made in SoapUI and code, and discovered that the .NET code was sending the soap action header as null and not an empty string.


To fix this I used the following line to correctly set the soap action in .NET:
webRequest.Headers.Add("SOAPAction", "\"\"");
It started to work as expected.

Conditional comments HTML for internet explorer 10

$
0
0
One method for displaying a message to users running outdated versions of internet explorer is via the use of conditional comments. For example the following block would only show for version 9 and below of internet explorer:
<!--[if lte IE 9]>
<p> Download Chrome today!</p>
<![endif]-->
 The problem with wanting to target version 10 of internet explorer is that it does not follow conditional comments and instead treats them as a standard comment. Therefore a CSS media query needs to be used to target this browser version.
@media all and (-ms-high-contrast: none) {
.myClass{ display:block; } /* IE10 */
*::-ms-backdrop, .myClass{ display: none } /* IE11 */
}
The example above will display a block when the browser is internet explorer 10 and hide it when internet explorer 11. Of course this block would be hidden by default and shown if necessary.

Sitecore WFFM targeting field inputs with jQuery

$
0
0
With current and older versions of Sitecore's Web Forms for Marketers module, it can often be necessary to make use of jQuery or JavaScript to extend functionality of the form. A common example would be conditional logic, such as if field A has value/selection show field b.

The problem is that the fields output with long ids which contain information such as the form id along with containing placeholder and ordering of the element. Instead of targeting by such a long id, for any custom WFFM form logic I prefer to target via the field id alone.

This can be done by using the jQuery attribute ends with selector. An example for an input field would be:

$("input[id$='9047F37B17F245AE9F56ABBDB1934510']")
This will find the input element for a given Sitecore form field.

Sitecore WFFM 2.5 customizing field output HTML with web forms

$
0
0
Working on a Sitecore 7.5 instance, along with web forms for marketers 2.5, I came across a requirement to implement Bootstrap styling across the form fields. Because the site wasn't running on MVC it wasn't as simple as editing the views for each field type (found in "/Website/Views/Form/EditorTemplates").

Instead I needed to create my own version of each field type I was editing and change how the field was output. For example with the single line of text field, it is defined in Sitecore under: /sitecore/system/Modules/Web Forms for Marketers/Settings/Field Types/Simple Types. As you can see it then references a DLL and Class:


This class inside the DLL looks like:
using Sitecore.Form.Core.Attributes;
using Sitecore.Form.Core.Visual;
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Sitecore.Form.Web.UI.Controls
{
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof (IDesigner))]
public class SingleLineText : RegexInputControl
{
private static readonly string baseCssClassName = "scfSingleLineTextBorder";

[VisualCategory("Validation")]
[VisualProperty("Maximum Length:", 2000)]
[DefaultValue(256)]
public int MaxLength
{
get
{
return this.textbox.MaxLength;
}
set
{
this.textbox.MaxLength = value;
}
}

[VisualProperty("Minimum Length:", 1000)]
[DefaultValue(0)]
[VisualCategory("Validation")]
public int MinLength { get; set; }

[DefaultValue("scfSingleLineTextBorder")]
[VisualProperty("CSS Class:", 600)]
[VisualFieldType(typeof (CssClassField))]
public new string CssClass
{
get
{
return base.CssClass;
}
set
{
base.CssClass = value;
}
}

public SingleLineText(HtmlTextWriterTag tag)
: base(tag)
{
this.MaxLength = 256;
this.MinLength = 0;
this.CssClass = SingleLineText.baseCssClassName;
}

public SingleLineText()
: this(HtmlTextWriterTag.Div)
{
}

protected override void OnInit(EventArgs e)
{
this.textbox.CssClass = "scfSingleLineTextBox";
this.help.CssClass = "scfSingleLineTextUsefulInfo";
this.generalPanel.CssClass = "scfSingleLineGeneralPanel";
this.title.CssClass = "scfSingleLineTextLabel";
this.textbox.TextMode = TextBoxMode.SingleLine;
this.Controls.AddAt(0, (Control) this.generalPanel);
this.Controls.AddAt(0, (Control) this.title);
this.generalPanel.Controls.AddAt(0, (Control) this.help);
this.generalPanel.Controls.AddAt(0, (Control) this.textbox);
}
}
}
The OnInit method is then where the field it actually output, and this is where changes can be made to affect the output of the field (CSS classes and div nesting). The following example is a replacement class which outputs single line text like a bootstrap field.
using Sitecore.Form.Core.Attributes;
using Sitecore.Form.Core.Visual;
using Sitecore.Form.Web.UI.Controls;
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace MyProject.WFFM.Controls
{
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
public class SingleLineText : RegexInputControl
{
private static readonly string baseCssClassName = "form-group";

[VisualCategory("Validation")]
[VisualProperty("Maximum Length:", 2000)]
[DefaultValue(256)]
public int MaxLength
{
get
{
return this.textbox.MaxLength;
}
set
{
this.textbox.MaxLength = value;
}
}

[VisualProperty("Minimum Length:", 1000)]
[DefaultValue(0)]
[VisualCategory("Validation")]
public int MinLength { get; set; }

[DefaultValue("form-group")]
[VisualProperty("CSS Class:", 600)]
[VisualFieldType(typeof(CssClassField))]
public new string CssClass
{
get
{
return base.CssClass;
}
set
{
base.CssClass = value;
}
}

public SingleLineText(HtmlTextWriterTag tag)
: base(tag)
{
this.MaxLength = 256;
this.MinLength = 0;
this.CssClass = SingleLineText.baseCssClassName;
}

public SingleLineText()
: this(HtmlTextWriterTag.Div)
{
}

protected Panel titlePanel;

protected override void OnInit(EventArgs e)
{
this.textbox.CssClass = "scfSingleLineTextBox";
this.help.CssClass = "scfSingleLineTextUsefulInfo";
this.generalPanel.CssClass = "field-responsive";
this.title.CssClass = "control-label";
this.textbox.TextMode = TextBoxMode.SingleLine;
this.Controls.AddAt(0, (Control)this.generalPanel);
this.titlePanel = new Panel();
this.titlePanel.CssClass = "label-responsive";
this.titlePanel.Controls.AddAt(0, (Control)this.title);
this.Controls.AddAt(0, (Control)this.titlePanel);
this.generalPanel.Controls.AddAt(0, (Control)this.help);
this.generalPanel.Controls.AddAt(0, (Control)this.textbox);
}
}
}
This might not work for all cases, but serves as a base for how to edit the output of fields inside WFFM (in a web forms site).

Sitecore WFFM field contains content that may present a security risk

$
0
0
Users of a web forms for marketers form in production started raising issues with validation on the form which was returning the following message:
The [field name] field contains content that may present a security risk. Please enter appropriate information
This is traced back to the Assess Security Risk, Form Verification action. Effectively what this piece of code is doing is checking to ensure that fields in a WFFM form do not contain any of the following characters: "<", ">" and "&".


The users of the form where using and ampersand ("&") character - and this was required for form functionality.

There are two potential solutions to fix this issue on the form.

Removing the Assess Security Risk action

  1. In the content editor navigate to the web form
  2. In the view options (top ribbon) turn "Raw Values" on
  3. In the submit section, locate the "Check Actions" field
  4. Remove the following section from the field's XML value
  5. Disable the "Raw Values" view option 
<li id="{2D5B5061-747A-4477-BD41-E746EAFEB231}" unicid="89F18F7C96F4469A9470057CE421A115"><parameters /></li> 
Effectively this clears out the "Check Actions" node of the XML, however if you have added custom actions you will need to ensure the correct one is removed.

Modifying the Assess Security Risk code

  1. Create your own version of the Assess Security Risk code, the example below removed the check for the ampersand ("&")
  2. Navigate to the action's configuration - /sitecore/system/Modules/Web Forms for Marketers/Settings/Actions/Form Verification/Assess Security Risk
  3. Update the assembly field to that of your custom DLL
  4. Update the class field to that of your custom class
  5. Publish the item
using Sitecore.Data;
using Sitecore.Form.Core.Configuration;
using Sitecore.Form.Core.Controls.Data;
using Sitecore.Form.Core.Submit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace MyProject.WFFM.Validators
{
public class AssessSecurityRisk : BaseCheckAction
{
public string FailedMessage { get; set; }

public override void Execute(ID formid, IEnumerable<ControlResult> fields)
{
List<string> stringList = new List<string>();
foreach (ControlResult field in fields)
{
if (field.Value != null)
{
string str = HttpUtility.HtmlDecode(field.Value.ToString());
if (str.StartsWith("<item>"))
str = str.Replace("<item>", string.Empty).Replace("</item>", string.Empty);
if (str.IndexOfAny(new char[3] { '<', '>' }) >= 0)
stringList.Add(field.FieldName);
}
}
if (stringList.Count > 0)
throw new Exception(string.Format(this.FailedMessage ?? (stringList.Count == 1 ? ResourceManager.Localize("VALIDATE_INPUT_FAILED") : ResourceManager.Localize("VALIDATE_INPUT_FAILED_MULTIPLE")), (object)string.Join(", ", stringList.ToArray())));
}

public override ActionState QueryState(ActionContext context)
{
return ActionState.DisabledSingleCall;
}
}
}

Sitecore WFFM viewstate validation error

$
0
0
A fresh install of web forms for marketers had been deployed to a scaled 7.5 instance of Sitecore. The following error message was reported by a user:
Validation of the viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that <machineKey> configuration specifies the same ValidationKey and validation algorithm. AutoGenerate cannot be used in a cluster.
Looking into the web.config files the machineKey element was completely missing. The Sitecore scaling guide had the following to say:
In a single instance environment, you shouldn’t change the configuration.

If the environment contains two or more instances:

In the web.config file, set the validationKey and the decryptionKey attributes of the /configuration/system.web/machineKey element to a non-auto generated value. Ensure that the values are identical for all the instances within the environment and that the IsolateApps modifier is not present in either value.
Therefore a machine key generator can be used to generate a valid machine key. An example would be:
<machineKey validationKey='7652D32FB7D858DC44FA409A88FDB9AC8E9811C4F2F4174F138A7901F53CF8E759551BA8EBCD923B5FFEE87737BDA8DA18337BDE51E7C89934B4B1D4F3C84F01' decryptionKey='8158C85A02EADC24CDD400E2E71D2D77B6B3A14E4EABD041'   validation='SHA1'/>
Take note that IsolateApps is not present after either of the keys and that a key is set rather than AutoGenerate.

Sitecore viewing and querying MongoDB

$
0
0
When working with Sitecore it can beneficial to be able to view the contents of MongoDB. This comes in handy for tasks such as ensuring a user is added to a contact list or perhaps your custom facets are populating with data as expected.

This will require Robomongo, which put simply is graphical management tool for MongoDB. The main feature of this tool that is relevant to this blog post, is the ability to view and query the data. It does a whole lot more, but one interesting feature worth mentioning is that "First MongoDB tool with fully asynchronous, non-blocking UI".

After installing Robomongo, you can then give it a connection to your local MongoDB instance. This is likely to be via the connection string: localhost:27017. Once it loads up you will see all of the available databases in the left pane.


Expand the analytics database for the instance of Sitecore that you are working on. In this case I am working with the contacts, so will be querying on this.


You are now given an empty query that shows all of the contacts for your Sitecore instance.


If I wanted to find a user with a specific email address, the query would be:
db.getCollection('Contacts').find({"Emails.Entries.MessageProvider.SmtpAddress":"1@email.com"})


You will notice that the query is a dot notation of the strucuture of the MongoDB object and in this case is looking for a string match.


However sometimes, you might want a more dynamic query. Such as all users who have an email address added. The query for this one would be:
db.getCollection('Contacts').find({"Emails.Entries.MessageProvider.SmtpAddress":{$ne:null}})

These are just a couple of quick examples of how to view and query the contents of your Sitecore MongoDB.

Sitecore Rocks SSL error

$
0
0
When attempting to use Sitecore Rocks on a local Sitecore instance that is set to use a secure connection, the following error was appearing when testing the connection.
Could not establish trust relationship for the SSL/TLS secure channel with authority 'host name'.

The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

The remote certificate is invalid according to the validation procedure.


In my case I was using the IIS Express Development Certificate which comes by default with the IIS install. The first thing to check is to ensure that you are using the host name which corresponds with the certificate you are using. In this case the host name localhost is expected.


I was using another host name which is what was causing this error, by changing the host to localhost it worked as expected.

If this doesn't work for you then it may be that the certificate is not trusted. The following article will provide details for trusting your certificate.

Sitecore custom contact facet error on Experience Profile

$
0
0
After successfully implementing a custom contact facet inside Sitecore, the next step was then to display this data on a custom tab inside the Experience Profile.

Once all of the required steps were completed, the following error was appearing on the page and no data was displaying:
No pipeline was found for View [name]

This traces back to the configuration file where the data access layer (query, population, etc.) is registered.


In the example above, the XML element is titled "employee". Which then means that the JavaScript file which is adding the new custom tab should reference it inside the base URL for the service.
var baseUrl = "/sitecore/api/ao/v1/contacts/" + contactId + "/intel/employee";
Ensuring these two variables matched, stopped the error from occurring.
Viewing all 287 articles
Browse latest View live