SaaS CMS has officially launched! Learn more now.

Update a User in both CMS & Commerce


In our eCommerce project we have a 'Personal Details' section where a user can do a number of things:

  1. Update their Salutation (Mr, Mrs etc.)**
  2. Update First and Second Name
  3. Update Date of Birth
  4. Update Gender**
  5. Change Password
  6. Change Username**

**These fields are added to the [dbo].[mcmd_MetaEnum] and [dbo].[cls_Contact] tables in Commerce via an InitilizationModule (see previous posts here and here)

My question is, what steps do I need to take to ensure that I can successfully update a User's details and have it synchronize across both the CMS databases and the Commerce databases?

I am aware that I can get the current user via the below line

var user = CustomerContext.Current;

However, user doesn't expose any of my new MetaField values: GenderSalutationUsername? How do I access (and update) database fields that I have added myself?

My follow up question will then be: once I am able to update the user's personal details in Commerce how do I then ensure that the CMS database will share the same values?

Below you can see a screenshot of the [dbo].[AspNetUsers] table. The only value that may change and need to be updated in the CMS as well Commerce is the UserName value.  

Is this as straightforward as the below?

var userProvider = ServiceLocator.Current.GetInstance<UIUserProvider>();
var httpContext = ServiceLocator.Current.GetInstance<IHttpContextAccessor>();
var username = httpContext.HttpContext.User.Identity.Name;         
var userInfo = userProvider.FindUsersByNameAsync(username, 10, 10).FirstOrDefaultAsync();
userInfo.Result.Username = "change username";

// do I need to run a save method here or is it automatically saved?
Edited, Jun 14, 2022 15:19

MetaFields are only part of the Commerce backing data storage. You'll have meta fields for the commerce customer with a number out of the box and the ability to define your own.

AspNetUsers is part of the identity table, there's no meta fields here this is down to the user data type which you use for identity.  You'd just update the values that are properties of the user data type you use for your user record.


So you'll need to update both if you want to keep them in sync when changes happen but I usually just only keep commerce as the source of truth for non standard values

Jun 14, 2022 16:41

As far as username goes it should be something like

// get user object from the storage
var user = await userManager.FindByIdAsync(userId);

// change username and email
user.Username = "NewUsername";
user.Email = "";

// Persiste the changes
await userManager.UpdateAsync(user);
Jun 14, 2022 16:44

Thanks Scott, however I'm not sure you have answered one of my questions:

However, user doesn't expose any of my new MetaField values: Gender, Salutation & Username? How do I access (and update) database fields that I have added myself?

After defining my own new fields for the [dbo].[cls_Contact] table, how do I then interact with those fields programmatically? At present, running the following code doesn't expose my new fields. I would expect to see GenderSalutation Username appear:

Jun 15, 2022 8:42
Scott Reed - Jun 15, 2022 9:34
From your description I thought you were successfully updating the customer values but wanted to sync the fields in the identity table in the CMS as you said in the CMS database and posted the table. Quan has answered but that's commerce values. My response was about the identity table which is the user table used in CMS

For the custom fields, you can access them by 

contact["FieldName"] = "FieldValue";

Jun 15, 2022 8:46

Thanks Quan, will that update the database straight away or do you then need to run a save method after?

Jun 15, 2022 8:49

You should need to call AcceptChanges(). it's only the assignment :) 

Jun 15, 2022 12:46

Hi again Quan, I am having issues updating a user from the [dbo].[cls_Contact] table.

I followed one of your blogs on how to grab a specific user from the table via their email address (annoyingly, I can't find it now). I now need to update some of the values of the user and then save the changes.

In your earlier comment you mention calling 'AcceptChanges()' but I can't see where that method is? You can see my attempt below with 'SaveChanges()' but I get the following error. Any thoughts?

Jun 20, 2022 18:51

nathano, are you using aspnet identity? Why not grab the commerce user from from ApplicationUserManager.FindByEmail instead?

inject ApplicationUserManager<SiteUser> into your ctor then call FindByEmail(). Try saving then.

Jun 21, 2022 10:38

Surjit, I need to update the [dbo].[cls_Contact] table specifically and update the fields. This is not using ASP.NET Identity because that does not give me access to the table.

In my simplified approach below I have take the UserId from a default user that comes with Commerce. You can see the highlighted user below from  [dbo].[cls_Contact] 

If I debug my code I can:

  1. Get the user by invoking the GetContactById() method
  2. Access all of the fields from the [dbo].[cls_Contact] table
  3. Update these fields (I can see when debugging that the new field values are being assigned)

However, when I invoke SaveChanges() I keep receiving an 'Object reference not set to an instance of the object' error. Why does this keep happening? What is not being instantiated? 

var placeholderEmail = "";
var placeholderId = new Guid("4DC8C10F-1902-42DD-874C-CA6684E327EC");
var placeholderAddress = CustomerAddress.CreateInstance();
var context = CustomerContext.Current.GetContactById(placeholderId);
context.LastName = "sampleName";

// the below fields have been added via Initialization Modules
context["AcademicTitle"] = "Dr.";
context["Salutation"] = "Mr";

// I have even added placeholder values below to avoid the error
context.PreferredBillingAddress = placeholderAddress;
context.PreferredShippingAddress = placeholderAddress;

Edited, Jun 21, 2022 13:25

I honestly cant see anything out of the ordinary with the code you provided.

  1. Is there a stack trace along with the object reference error?
  2. Can you check your variable context is actually being assigned a CustomerContact object
Jun 21, 2022 15:34

The problem is how you are trying to create the address.  Please see here for example on how to add new address to customer.  Also note you should save the contact first before adding the address.

Edited, Jun 21, 2022 16:01

Mark, I have been investigating the CustomerService class in Foundation and, more specifically, CreateFoundationContact() and the SetPreferredAddresses() methods to try and resolve this and I can see that they follow your guide on setting the addresses after the contact has been saved.

I have attempted to recreate this locally but I am still recieving the same error. The error arrives when I try to invoke SaveChanges()

You can see my code below:

      private void CreateCommerceUser()
         var contact = CommerceContact.New();

         contact.FirstName = "Fname";
         contact.LastName = "Lname";
         contact.Email = "";
         contact.UserId = "";
         contact.RegistrationSource = "StartupUser";
        // error arrives when the below is invoked: 'Object not set to an instance of an object'
     // at present this code is never run
      private void SetPreferredAddresses(CustomerContact contact)
         var changed = false;

         var publicAddress = contact.ContactAddresses.FirstOrDefault(a => a.AddressType == CustomerAddressTypeEnum.Public);
         var preferredBillingAddress = contact.ContactAddresses.FirstOrDefault(a => a.AddressType == CustomerAddressTypeEnum.Billing);
         var preferredShippingAddress = contact.ContactAddresses.FirstOrDefault(a => a.AddressType == CustomerAddressTypeEnum.Shipping);

         if (publicAddress != null)
            contact.PreferredShippingAddress = contact.PreferredBillingAddress = publicAddress;
            changed = true;

         if (preferredBillingAddress != null)
            contact.PreferredBillingAddress = preferredBillingAddress;
            changed = true;

         if (preferredShippingAddress != null)
            contact.PreferredShippingAddress = preferredShippingAddress;
            changed = true;

         if (changed)

And then, my CommerceContact class is below and has been influenced by the FoundationContact class.

public class CommerceContact
      public CommerceContact() => Contact = new CustomerContact();
      public CommerceContact(CustomerContact contact) => Contact = contact ?? new CustomerContact();
      public CustomerContact Contact { get;}

      public Guid ContactId 
         get => Contact?.PrimaryKeyId ?? Guid.Empty;
         set => Contact.PrimaryKeyId = new PrimaryKeyId(value);

      public string FirstName
         get => Contact.FirstName;
         set => Contact.FirstName = value;

      public string LastName
         get => Contact.LastName;
         set => Contact.LastName = value;

      public string FullName
         get => Contact.FullName;
         set => Contact.FullName = value;
      public DateTime? BirthDate
         get => Contact.BirthDate;
         set => Contact.BirthDate = value;

      public string Email
         get => Contact.Email;
         set => Contact.Email = value;
      public CommerceOrganization CommerceOrganization
         get => Contact != null && Contact.ContactOrganization != null ? new CommerceOrganization(Contact.ContactOrganization) : null;
         set => Contact.OwnerId = value.OrganizationEntity.PrimaryKeyId;

      //public string UserLocationId
      //   get => Contact.GetStringValue("UserLocation";
      //   set => Contact[Constant.Fields.UserLocation] = value;

      public string UserId
         get => Contact.UserId;
         set => Contact.UserId = $"String:{value}";
      public string RegistrationSource
         get => Contact.RegistrationSource;
         set => Contact.RegistrationSource = value;

      public bool AcceptMarketingEmail
         get => Contact.AcceptMarketingEmail;
         set => Contact.AcceptMarketingEmail = value;

      public DateTime? ConsentUpdated
         get => Contact.ConsentUpdated;
         set => Contact.ConsentUpdated = value;

      public void SaveChanges() => Contact.SaveChanges();
      public static CommerceContact New() => new CommerceContact(CustomerContact.CreateInstance());

Jun 22, 2022 13:58

Nathano, I copy / pasted your code minus setting the address and it works just fine. Saves it to the database.

I suspect your issue isn't the code. I executed yours from a Home Controller, so I know all the commerce context has loaded up.

Where are you executing yours? mvc controller? schedule job? maybe a http endpoint?

Jun 22, 2022 16:24

Surjit, I had the code in its own `UserManager` class, so not in a Controller. I just tried the below code in an action method within a controller and I still get the error. Am I missing some additional setup to make this work? How do I know whether my 'commerce context' has loaded up correctly? Really bizarre.

      public IActionResult UpdatePersonalDetails()
         Guid contactId = Guid.NewGuid();

         CustomerContact contact = CustomerContact.CreateInstance();
         contact.FirstName = "Fname";
         contact.LastName = "Lname";
         contact.Email = "";
         contact.UserId = "";
         contact.RegistrationSource = "StartupUser";


         return Ok();
Jun 22, 2022 18:54

Hmm...well for starters you said you have an ecommerce project...can I assume it's LIVE? and also have other commerce features working? Such as pulling catalogue product info, adding to cart and checking out?

If the answer is yes then maybe we need to look at anything custom you've added to the CustomerContact object to see if anything is marked as required.

if the answer is no then I would look at the Startup.cs and compare it to Foundation. Make sure you have all the services called.

In your first post you make a reference to AspNetUsers which implies you have identity installed. In the startup.cs you may need to make sure the connectionstring setup against identity is the commerce db connection string, not the cms db.

Jun 22, 2022 22:47

This has been resolved now.

Whenever I was working with the  [dbo].[cls_Contact] table I was receiving an 'Object not instantiated to an instance of an Object' error but no reference to what object. 

After receiving help from a colleague it became clear that the new MetaField values that I added to the [dbo].[cls_Contact] table did not have 'isNullable' set to to true. Therefore, I had fields in my table without values that were, technically, not allowed to be null.

To fix this I did the following:

  1. cleared my database
  2. updated my InitializationModule to ensure the new fields can be nullable
  3. re-ran my project, which re-ran my InitializationModule
  4. then used the below code to save a user
  5. success
      // the below code is technically to update a user but the concept is the same.

      public bool UpdateCommerceUser(string salutation, string academicTitle, string firstName, string lastName, string birth, string gender)
         var placeholderId = new Guid("4DC8C10F-1902-42DD-874C-CA6684E327EC");
            var context = CustomerContext.Current.GetContactById(placeholderId);

            context["Salutation"] = salutation;
            context["AcademicTitle"] = academicTitle;
            context.FirstName = firstName;
            context.LastName = lastName;
            context.FullName = $"{firstName} {lastName}";
            context["Gender"] = gender;


            return true;
         catch (ObjectNotFoundException ex)
            return false;
Edited, Jun 23, 2022 13:57
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.