Impersonating Customer Context Internal Cach Error (Commerce 11.8.2)

Vote:
 

I've got some code for working with syncing a commerce user on version 11.8.2

Firstly I'm injecting the impersonation service

internal Injected UserImpersonationService { get; set; }

Then I'm getting the users addresses

var userPrinciple = UserImpersonationService.Service.CreatePrincipal(username);
var customerContact = userPrinciple.GetCustomerContact();
var addresses = customerContact.ContactAddresses.ToList();

This code is working perfectly however after running once I'm getting the followingexception thrown with a Object Reference error

at Mediachase.BusinessFoundation.Data.Business.BusinessManager.Execute(Request request)
   at Mediachase.BusinessFoundation.Data.Business.BusinessManager.List(String metaClassName, FilterElement[] filters)
   at Mediachase.Commerce.Customers.CustomerContext.InnerGetAllContactAddresses(CustomerContact contact)
   at Mediachase.Commerce.Customers.CustomersCache.<>c__DisplayClass5_0`1.b__0()
   at EPiServer.Framework.Cache.ObjectInstanceCacheExtensions.ReadThrough[T](IObjectInstanceCache cache, String key, Func`1 readValue, Func`2 evictionPolicy)
   at Mediachase.Commerce.Extensions.ObjectInstanceCacheExtensions.ReadThrough[T](IObjectInstanceCache cache, Boolean useCache, String cacheKey, IEnumerable`1 masterKeys, TimeSpan duration, Func`1 load)
   at Mediachase.Commerce.Extensions.ObjectInstanceCacheExtensions.ReadThrough[T](IObjectInstanceCache cache, String cacheKey, IEnumerable`1 masterKeys, TimeSpan duration, Func`1 load)
   at Mediachase.Commerce.Customers.CustomersCache.ReadThrough[T](String key, IEnumerable`1 masterKeys, TimeSpan timeout, Func`1 load)
   at Mediachase.Commerce.Customers.CustomerContext.GetContactAddresses(CustomerContact contact)

Any ideas?

#196153
Edited, Aug 20, 2018 18:00
Vote:
 

Also if I debug I don't get the issue, only when the code is executing as standard

#196154
Aug 20, 2018 18:07
Vote:
 

It seems popping a Thread.Sleep(500) fixes the problem so I think something weird is going on with the caching of the addresses

#196155
Aug 20, 2018 18:18
Vote:
 

It works for me (on 11.8.2), I can get contact addresses many times without exception.

var userPrinciple = ServiceLocator.Current.GetInstance<IUserImpersonation>().CreatePrincipal("admin@example.com");
var customerContact = userPrinciple.GetCustomerContact();
var addresses = customerContact.ContactAddresses.ToList();

I'm not sure about UserImpersonationService.

#196170
Aug 21, 2018 10:51
Vote:
 

Thanks, something weird went on when pasting, I'm using IUserImpersonation same as yourself it's just injected. That's effectivly the same code I'm running just with the injection differences, although it's running in a task so is in a separate thread which may impact it, although the small thread delay seems to be working

#196171
Aug 21, 2018 10:57
Vote:
 

I think the task running in separate thread causes smthing in BusinessManager.Execute() (which is quite complex)

Could you give more info about which variable is null?

#196174
Aug 21, 2018 11:20
Vote:
 

There's nothing in the exception as it's a null reference that tells me which object is null although I've had similar issues with a previous version of the code which just stopped working and that was having issues around the HttpContext although I'm passing through CallContext.HostContext = context; with a pointed to the active context with the code that's running. At the moment all I have is the error I've pasted above, there was little more in the exception detail. 

#196175
Aug 21, 2018 11:27
Vote:
 

You could may be able to replicate what I'm doing by running your code you posted in a task calling the method with that code in with

Task.Run(() =>
{
CallContext.HostContext = context;
METHOD
});

In my case this code is being executed in the in the authentication steps of after login

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                Provider = new CookieAuthenticationProvider
                {
                    // Enables the application to validate the security stamp when the user logs in.
                    // This is a security feature which is used when you change a password or add an external login to your account.
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager<ApplicationUser>, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => manager.GenerateUserIdentityAsync(user)),
                    OnResponseSignedIn = OnResponseSignedIn
                },
                SlidingExpiration = true,
                ExpireTimeSpan = TimeSpan.FromMinutes(30)
            });
private void OnResponseSignedIn(CookieResponseSignedInContext cookieResponseSignedInContext)
        {
                var context = System.Web.HttpContext.Current;
                Task.Run(() =>
                {
                    CallContext.HostContext = context;
                    METHOD;
                });
        }
#196176
Aug 21, 2018 11:30
Vote:
 

It works for me :)

        public void Configuration(IAppBuilder app)
        {
            app.AddCmsAspNetIdentity<SiteUser>(new ApplicationOptions
            {
                ConnectionStringName = _connectionStringHandler.Commerce.Name
            });

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Login"),
                Provider = new CookieAuthenticationProvider
                {
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager<SiteUser>, SiteUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => manager.GenerateUserIdentityAsync(user)),
                    OnApplyRedirect = context => context.Response.Redirect(context.RedirectUri),
                    OnResponseSignOut = context => context.Response.Redirect(UrlResolver.Current.GetUrl(ContentReference.StartPage)),
                    OnResponseSignedIn = OnResponseSignedIn
                },
                SlidingExpiration = true,
                ExpireTimeSpan = TimeSpan.FromMinutes(30)
            });

            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
            app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
            app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
        }

        private void OnResponseSignedIn(CookieResponseSignedInContext cookieResponseSignedInContext)
        {
            var context = System.Web.HttpContext.Current;

            Task.Run(() =>
            {
                CallContext.HostContext = context;

                var userPrinciple = ServiceLocator.Current.GetInstance<IUserImpersonation>().CreatePrincipal("admin@example.com");
                var customerContact = userPrinciple.GetCustomerContact();
                var addresses = customerContact.ContactAddresses.ToList();
            });
        }
#196179
Aug 21, 2018 12:20
Vote:
 

Note it seems to work the first few times but after a few hits then it's breaking. The delay I think is working so I guess I'll go with that

#196194
Aug 21, 2018 17:54
* 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.