Storing user profile image using Salesforce Connector with Sitecore

When using the salesforce connector with Sitecore, we came across the need to store user profile images as well in salesforce.
Once the connector is set up (which includes setup in Web.config / Domains.config and S4S.config), any user user profile interaction automatically happens with salesforce, and fields which are mapped in web.config with corresponding sitecore fields – will automatically get mapped / updated on these interactions!

The special case we came across, was with Profile images. Our site allowed the user to upload profile images, which we needed to store in salesforce, and additionally also wanted the image to show up in sitecore.

The solution we came up with, was to create a document folder in salesforce and upload all profile images there with the contact id as the file name as a document, and then store the url in the Sitecore user portrait field.

In the view, we added the form to upload images:

using (Html.BeginForm("SubmitProfilePhoto", "SharedUpdateProfilePhoto",
    FormMethod.Post, new Dictionary<string, object>
        {"enctype", "multipart/form-data"},
        {"role", "form"}
     <input type="file" accept="image/jpeg,image/gif,image/png" name="profilePhoto" id="profilePhoto" />

In the post method:

        public void SubmitProfilePhoto(HttpPostedFileBase profilePhoto)
            BinaryReader binaryReader = new BinaryReader(profilePhoto.InputStream);
            byte[] bytes = binaryReader.ReadBytes((int)profilePhoto.InputStream.Length);

            string documentId = S4SHelper.AddDocument(Convert.ToBase64String(bytes), profilePhoto.FileName.Substring(profilePhoto.FileName.LastIndexOf('.')));

            if (documentId != null)
                // Update Salesforce field in user object - which contains the profile picture document id
                S4SHelper.UpdateContactField(Constants.Salesforce.ContactFields.ContactProfilePhotoDocumentId, documentId);
                // Update profile image url in sitecore user profile                        
                Sitecore.Context.User.Profile.Portrait = S4SHelper.GetDocumentUrl(documentId);


Here’s the code used to add the document in salesforce:

public static string AddDocument(string base64FileContents, string fileExtension)
            if (string.IsNullOrWhiteSpace(_Salesforce_Profile_Image_Folder_Id)) return string.Empty;

            UserInformation userInformation = GetUserInformation();
            DocumentService documentService = new DocumentService(GetSalesforceSession);
            Document document;

            // If a document already exists for this user, delete it! 
            // (We dont want to update it, because image with the same url gets cached)
            if (!string.IsNullOrWhiteSpace(userInformation.ProfilePhotoDocumentId))
                document = documentService.GetByEntityId(userInformation.ProfilePhotoDocumentId);
                if (document != null)

            document = new Document
                Name = userInformation.ContactId + fileExtension,
                Body = base64FileContents,
                FolderId = _Salesforce_Profile_Image_Folder_Id,
                IsPublic = true

            SaveResult saveResult = documentService.Save(document);

            if (saveResult.success)
            return null;

Once the document is added in salesforce, the document url will give you the base document url of your salesforce instance, which you can use and replace the intended document id to get the right url for each new document created. This is what the S4SHelper.GetDocumentUrl(documentId) method does.


Notify sitecore user on account enable

Often when a new user is created (especially if created from the sitecore site – as an extranet user), we might find the need to have an approval process in place to ensure access to credible users only.

You can see more details on creating extranet users for your site at Creating an extended Sitecore user for your site

When the user is being created, you can automatically disable the user initially by adding this before user save:

user.IsApproved = false;

This would disable the user id:

Now when a user admin of your site, goes and enables the user after review, you might want to intimate the user that their account has been enabled and they now have the privileges that it comes with!

The enable user command which is executed when a user is enabled resides in the App_Config\Commands.config file:

  <command name="usermanager:enable" type="Sitecore.Shell.Framework.Commands.UserManager.Enable,Sitecore.Kernel"/>

You can override this command and add your own functionality to the existing needed functionality for enable which you can bring over from the reflected code of Sitecore.Kernel.dll.

Here’s a sample of getting this done:

  <command name="usermanager:enable" type="Sitecore72.Classes.EnableUserNotify, Sitecore72"/>

Code (This is reflected code from sitecore.kernel.dll with an additional method call for the notification. You could sure choose to write the code yourself for enable – after all you only need to toggle a user property at the end of the day, but this code will also handle the confirm messages and all error handling for you)

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Net.Mail;
using System.Text;
using System.Web.Security;
using Sitecore.ApplicationCenter.Applications;
using Sitecore.Diagnostics;
using Sitecore.Globalization;
using Sitecore.Shell.Framework.Commands;
using Sitecore.Shell.Framework.Commands.UserManager;
using Sitecore.Text;
using Sitecore.Web.UI.Sheer;
using Sitecore.Web.UI.WebControls;
using Sitecore.Web.UI.XamlSharp.Continuations;

namespace Sitecore72.Classes
    public class EnableUserNotify : Command, ISupportsContinuation
        /// <summary>
        /// Executes the command in the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public override void Execute(CommandContext context)
            Assert.ArgumentNotNull((object)context, "context");
            var userName = context.Parameters["username"];
            if (!ValidationHelper.ValidateUserWithMessage(userName))
            var parameters = new NameValueCollection();
            parameters["username"] = userName;
            ContinuationManager.Current.Start((ISupportsContinuation)this, "Run", new ClientPipelineArgs(parameters));

        /// <summary>
        /// Runs the pipeline.
        /// </summary>
        /// <param name="args">The args.</param>
        protected void Run(ClientPipelineArgs args)
            Assert.ArgumentNotNull((object)args, "args");
            ListString listString = new ListString(args.Parameters["username"]);
            if (args.IsPostBack)
                if (!(args.Result == "yes"))
                List<string> list = new List<string>();
                string key = string.Empty;
                foreach (string username in listString)
                    MembershipUser user = Membership.GetUser(username);
                    Assert.IsNotNull((object)user, typeof(MembershipUser));
                        user.IsApproved = true;


                        Log.Audit((object)this, "Enable user: {0}", new string[1]
                    catch (NotImplementedException ex)
                        key = "Sorry, this feature is not supported by the underlying provider implementation. Please contact the system administration for more details";
                    catch (NotSupportedException ex)
                        key = "Sorry, this feature is not supported by the underlying provider implementation. Please contact the system administration for more details";
                    catch (Exception ex)
                        key = ex.Message;
                        Log.Error("User can not be enabled", ex, (object)this);
                if (list.Count > 0)
                    StringBuilder stringBuilder = new StringBuilder();
                    foreach (string str in list)
                    SheerResponse.Alert(Translate.Text("The following users could not be enabled:\n{0}\nException:\n{1}", (object)((object)stringBuilder).ToString(), (object)Translate.Text(key)), new string[0]);
                if (listString.Count == 1)
                    SheerResponse.Confirm(Translate.Text("Are you sure you want to enable {0}?", new object[1]
            (object) listString[0]
                    SheerResponse.Confirm(Translate.Text("Are you sure you want to enable these {0} users?", new object[1]
            (object) listString.Count

        private void NotifyUser(User user)
            var emailMessage = new MailMessage
                From = new MailAddress(ConfigurationSettings.AppSettings["CompanyFromAddress"]),
                Subject = "You are a privileged member!",
                Body = user.FullName + ", you are now a privileged member of our club!"


            using (var client = new SmtpClient())

The corresponding smtp settings can be as usual found in the config:

        <network host="" port="25" userName="" password="" defaultCredentials="true" />

Creating an extended Sitecore user for your site

You might want to use the sitecore ASP.NET membership provider Core database to manage users for your sitecore site.

In that case, at some point during your site development, you will come across the need to create a new sitecore user from your site front end.
You might also want to have additional fields as is relevant to your application.
In this example, we are adding user address as additional custom fields.

The user template is available in the Core database of your sitecore instance.
The template is available at: /sitecore/templates/System/Security/User


You might also want to add a custom status field to be used by a site administrator – for user profile approval.

This field could point to a list of options also available in the core database:
Sample Template: /sitecore/templates/System/Security/User Profile Data/Profile Status Type

Options: /sitecore/content/Home/Data/Profile Status Types

Following is the code you could use to create the user:

Please note the code for default selection of the drop down field in the user template, and also the default ProfileItemId – which will determine which view the user will open in when you access the user from the User Manager console.

public bool CreateUpdateAccount(string firstName, string lastName, string emailAddress, string password,
            string addressLine1, string addressLine2, string city,
			string ddlCountriesText, string ddlStateText, string postalCode)
	var formData = new NameValueCollection();
	Sitecore.Security.Accounts.User user = null;

	formData["Name"] = firstName + " " + lastName;
	formData["Email"] = emailAddress;
	formData["Password"] = password;

	user = SecurityHelper.SitecoreSecurity.CreateSitecoreUser(formData);

	if (user != null)

		user.Profile.SetCustomProperty(Constants.UserCustomProperty.AddressLine1, addressLine1);
		user.Profile.SetCustomProperty(Constants.UserCustomProperty.AddressLine2, addressLine2);
		user.Profile.SetCustomProperty(Constants.UserCustomProperty.City, city);
		user.Profile.SetCustomProperty(Constants.UserCustomProperty.Country, ddlCountriesText);
		user.Profile.SetCustomProperty(Constants.UserCustomProperty.Region, ddlStateText);
		user.Profile.SetCustomProperty(Constants.UserCustomProperty.PostalCode, postalCode);

		// Constants.CoreDb.ItemGuid.PendingApproval - contains the GUID of the Pending Approval item in Core DB
		// in the folder: /sitecore/content/Home/Data/Profile Status Types
		user.Profile.SetCustomProperty(Constants.UserCustomProperty.ProfileStatus, Constants.CoreDb.ItemGuid.PendingApproval);

		// Constants.CoreDb.ItemGuid.PendingApproval has the guid of the item in Core at: /sitecore/system/Settings/Security/Profiles/User
		// This is to ensure that the default mode of the site created user has these custom properties.
		user.Profile.ProfileItemId = Constants.CoreDb.ItemGuid.SecurityProfileUser;

		return true;
	return false;

Security Helper method:

public static User CreateSitecoreUser(NameValueCollection formData)
	var fullUsername = Sitecore.Context.Domain.GetFullName(Guid.NewGuid().ToString());
	var user = User.Create(fullUsername, formData["Password"]);

	using (new SecurityDisabler())
		// Constants.CoreDb.ItemGuid.PendingApproval has the guid of the item in Core at: /sitecore/system/Settings/Security/Profiles/User
		user.Profile.ProfileItemId = Constants.CoreDb.ItemGuid.SecurityProfileUser;
		user.Profile.FullName = formData["Name"];
		user.Profile.Email = formData["Email"];
	return user;

Following is a user as seen from the user manager which was created from a site (note the ‘extranet’ domain)


Here is the populated droplink field:

For user login, the following code can be used:

Sitecore.Security.Authentication.AuthenticationManager.Login(domainName + @"\" + userName, password, false);

To validate user:

System.Web.Security.Membership.ValidateUser(domainName + @"\" + userName, password));

To access the custom fields:

var address1= currentUser.Profile.GetCustomProperty(Constants.UserCustomProperty.AddressLine1);

You can also get the list of users pending approval (if you wanted to for a custom User Admin page):

    public static List<User> GetUsersPendingApproval()
		IFilterable<User> allUsers = UserManager.GetUsers();

		// Constants.CoreDb.ItemGuid.PendingApproval - contains the GUID of the Pending Approval item in Core DB
		// in the folder: /sitecore/content/Home/Data/Profile Status Types
		return allUsers.Where(user => user.Profile.GetCustomProperty("Profile Status") == Constants.CoreDb.ItemGuid.PendingApproval).ToList();