Hi Bo Brinch,
I am also facing same issue. May I know if you have found any resolutoin for this.
//Mounesh
Hi Bo
Do you create/save a CustomerContact
entity on the user's first login? If not, you seem to get a new dummy CustomerContact
instance everytime you call CustomerContext.CurrentContactId
. Because it cannot find a matching entity in the database, yet the user is not un-authenticated anymore.
Basically, make sure that the database contains a CustomerContact
entity, with the UserId
property matching the unique user ID of the Azure user.
For anonymous (non logged-in) users, the CurrentContactId
is stored in the buiilt-in anonymous cookie (in ".ASPXANONYMOUS" by default). But as soon as the user logs in, CurrentContactId
is found according to the above described logic.
Hi Stefan,
I am also facing same issue as Bo.
Do you mean we have to store CustomerContact entity in EPiServer even after implementing SIngle-sign on ?
Exactly, Mounesh.
As part of the regular user registration process, we need to create a CustomerContact
upon creating/saving a new user account.
However, when you do Single-Sign-On (SSO), there is no regular registration process.
In this case, I check whether a CustomerContact exists for the unique user ID that was returned from the SSO login. If it doesn't exist, simply create one on the login callback method (filling as many properties as possible). Remember to set the UserID property of the CustomerContact
to the ID of the returned user.
Hi Stefan,
The required field is of type GuId. The unique ids we get from ADFS are like EmailId, USerId (string), will these ids work for the Cart and Orders ?
Hi Mounesh
CustomerContact.UserId
is supposed to be a string. If you provide it with a string, the user ID is supposed to prefix it with "String:".
To make it easy, you can generate the value for the UserId
property by calling MapUserKey.ToTypedString
(use constructor injection of MapUserKey
). It will take care of casting (in case the ID is not a string) and correctly prefixing the user ID.
Do you have either ServiceAPI installed, or do you have SuppressDefaultHostAuthentication called anywhere in your code?
Hi Stefan,
Thanks for you solution suggested I will try the solution.
Just for your information, I am using PrincipalInfo.CurrentPrincipal.GetContactId() and CustomerContext.Current.CurrentContactId which are of type GuId.
You are welcome, Mounesh. Please let me know how it works out for you.
Those two methods you refer to returns the Id of the CustomerContact
entities. The UserId
is a string property that defines the login user that the CustomerContact
is linked to.
By the way. When you create a CustomerContact
, the value of the UserId
(besides the mentioned prefix) has to match the value of the logged-in user's Identity.Name
property. That could be an email, a GUID value or something else, depending on your authentication provider.
Hi Stefan,
I have tried using UserId, even hardcoding "String:Email", howvever below function takes GuId as first parameter. So It's not working.
_orderRepository.LoadCart<ICart>(_customerContext.CurrentContactId, name, _currentMarket);
Please let me know if you have any comments or suggestions.
I think you misunderstood me, Mounesh.
After the visitor returns from Azure as a logged-in user, check if he/she has a CustomerContact
already. If not, create one.
Below is a quick example. You can put it somewhere in your login callback. In short, it tries to load a CustomerContact
for the logged-in user, and create/save one if necessary.
IPrincipal userPrincipal = PrincipalInfo.CurrentPrincipal;
CustomerContact contact = _customerContext.GetContactByUsername(userPrincipal.Identity.Name);
if (contact == null)
{
// TODO: Get user's email from the identity provider or ClaimsIdentity.
string email = "user@domain.tld";
// Using this method (instead of the default) correctly sets the UserId for us, using the logged-in user's IPrincipal.
contact = CustomerContact.CreateInstance(userPrincipal, null, email);
// TODO: Fill as many fields as possible, using data from the identity provider.
// This is just a hardcoded example.
contact.FirstName = "FirstName";
contact.LastName = "LastName";
contact.FullName = "FirstName LastName";
contact.SaveChanges();
}
You don't have to make any changes to the way you load the cart. The following line will work, since now the user has a CustomerContact
.
ICart cart = _orderRepository.LoadCart<ICart>(_customerContext.CurrentContactId, name, _currentMarket);
Hi Stefan,
It is creating CustomerContact
object. But the issue is _customerContext.CurrentContactId value is changing continuously.
Lets assume When I add a prodcut to cart the value _customerContext.CurrentContactId is {1-2-3}, the product gets added successfully. When I try to retrieve the products from cart the value of _customerContext.CurrentContactId will be {4-5-6}. Then it returns empty cart for the user.
Did you create the object yourself (similarly to example)? Or did Commerce just create an object when you call _customerContext.CurrentContactId
?
Basically what I'm asking is: Are you seeing an auto-generated/transient CustomerContact
object? Can you find the contact using Commerce Manager?
If you see the transient object, it will be changed every time you call _customerContext.CurrentContactId
. That is why I suggest that you both create and save the object yourself before using it (which is what my sample code shows).
Hi Quan,
We have not installed ServiceAPI and dont have SuppressDefaultHostAuthentication.
Could you please tell where it is required and alos any documentation for this related to Single Sign On.
Are you in the same company with Bo - i.e. are you working with same problem?
It's not that ServiceAPI is required (nor SuppressDefaultHostAuthentication()). It's the way around, ServiceAPI, which calls SuppressDefaultHostAuthentication internally, remove the authentication cookie that required for customerContext.CurrentContactId to work properly. If you don't have those then I don't have a good explanation of why it does not work for you.
Hi Quan,
Thanks for the explaination on the ServiceAPI.
Yes we both work for same company ( based on his profile details. I work for Capgemini India and he works for Capgemini Denmark. But not for same Project. I just came across this page when I was looking for some solution for the issue and found that, Bo also has faced it.
Hi Guys,
Reviving this thread again.
I am experiencing the same issue, and it happens randomly for anonymous users. I do know "WHY" it's happening but don't know how to solve it.
The .ASPXANONYMOUS cookie gets randomly refreshed with a new value (notoriously iOS) which causes the cart to vanish because CustomerContext is generated off this cookie. This directly impacts the conversion rate, because the user needs to add all items back to the cart which is extremely annoying. NOTE: This only happens for guest checkout users (considering logged-in users don't look at the .ASPXANONYMOUS cookie).
Also, we don't have SuppressDefaultHostAuthentication set anywhere.
Any help would be greatly appreciated.
@Aniket, are you sure it's not connected to a missing machine key configuration? There's a risk that if you restart (for example by deploying code) your IIS website without having a specified machine key in the web.config, the website will generate a new machine key and thereby also create a new .ASPXANONYMOUS cookie (because the hashing algo changed).
Hi
I have this method which checks if a cart already exists:
protected ICart GetExistingCart(string name) => _orderRepository.LoadCart<ICart>(_customerContext.CurrentContactId, name, _currentMarket.GetCurrentMarket().MarketId);
If the method returns null, I create a new cart:
cart = _orderRepository.Create<ICart>(_customerContext.CurrentContactId, name);
SaveCart(cart);
This is used in the start of, and during the checkout flow.
Now, the thing is that our site generally allows for a user to signin to access some non-public areas of the site (pages that are not related to the checkout flow). Signin is with Owin (in Azure).
If the user is logged in, and afterwards decides to go to the checkout flow, Commerce's
_customerContext.CurrentContactId
changes constantly, and thus every time I callGetExistingCart
for the same user, it won't find any cart. If I debug the code in Visual Studio, I can see that for every line I step over,_customerContext.CurrentContactId
changes.If however, user is not signed in already,
_customerContext.CurrentContactId
stays the same, and cart can be created and retrieved as expected during checkout.Anyone knows what the problem can be with this
_customerContext.CurrentContactId
and its constant change of value when signed in with Owin?Commerce version is 11.8.3.