Make The Epi Commerce SiteContext Work From Session Instead Of Cookies

I had a requirement in one of my Epi-Commerce projects that whenever a website visitor signed up to the website and created an account, that account was locked to the default currency for their current location.  This could not be changed as it could potentially allow people to get items at a discounted rate.

In a normal scenario, to get the current currency you would normally use the Epi Commerce SiteContext instance and use the Currency property, however, by default this uses a cookie and we had security concerns that a user might be able to cheat the system by changing the currency in their cookie.  Instead we thought it would be a better approach to use a session value and store the currency when it was needed.

My initial thought was to stick some code in the base page and product controller and bypass the Epi Api altogether, however, this approach definitely wasn’t ideal.  Firstly, all the developers in the team would have to remember to not use some of the Epi API calls (which in a big team was very unlikely to happen) and, worse, it would also mean we wouldn’t be able to use some parts of the Epi API.

The approach we finally decided upon was to create our own project based SiteContext that inherited from the Epi SiteContext and in the initialisation module tells structure map to use my custom version instead of the Epi version.  Intercepting the request this way allowed me to contain all my code in one area and allowed the Epi API to carry on doing its thing while the other dev’s on the project could carry on working, oblivious to the way it worked had changed.  Perfect!

In our situation we had two ways the currency could be set:

Anonymous users: Should use the default currency set for their location.  The code to do this was done in a GeoLocation helper.  Based on their current IP a currency code will re returned. We then had a currency repository that we could throw the country code at and we would get back the default currency for that location

Logged In users: Should always use the currency stored against their user account.  In our case this was a third party customer service.  When a site user logged in, the currency returned should be set based on this value

After we had the correct currency to display, I then stored the value in session state so it didn’t have to do the costly look-up again.  This was done using MemoryCache stored against either the HttpContext.Current.Request.AnonymousID value for anonymous users, or the ProviderKey from the MembershipUser class for logged in users.

The Code

Memory Cacher Class

public class MemoryCacher
{
public object GetValue(string key)
{
var memoryCache = MemoryCache.Default;
return memoryCache.Get(key);
}
public bool Add(string key, object value, DateTimeOffset absExpiration)
{
var memoryCache = MemoryCache.Default;
return memoryCache.Add(key, value, absExpiration);
}
public void Delete(string key)
{
var memoryCache = MemoryCache.Default;
if (memoryCache.Contains(key))
memoryCache.Remove(key);
}
}

The above code will allow you to add and remove items into global cache. The next part is creating your Custom SiteContext

public class CustomSiteContext : SiteContext
{
private readonly HttpContext context;
public CustomSiteContext()
{
context = HttpContext.Current;
}
public override Currency Currency
{
get
{
return HttpContext.Current.User == null || !HttpContext.Current.User.Identity.IsAuthenticated
|| string.IsNullOrEmpty(HttpContext.Current.User.Identity.Name)
? ProcessAnonymous(context)
: ProcessAuthenicatedUser(context);
}
set
{
if (!context.User.Identity.IsAuthenticated)
MemoryCacher.Add(string.Format("{0}:currency", context.Request.AnonymousID), value.CurrencyCode, new DateTimeOffset(DateTime.Now.AddDays(1)));
}
}
private Currency ProcessAnonymous(HttpContext context)
{
var currency = MemoryCacher.GetValue(string.Format("{0}:currency", context.Request.AnonymousID));
if (currency != null && !string.IsNullOrEmpty(currency.ToString()))
return currency.ToString();
var currentCurrency = "EUR"; // TODO change this get the currency from your repo etc...
MemoryCacher.Add(
string.Format("{0}:currency", context.Request.AnonymousID),
currentCurrency,
new DateTimeOffset(DateTime.Now.AddDays(1)));
return new Currency(currentCurrency);
}
private Currency ProcessAuthenicatedUser(HttpContext context)
{
var windowsUser = Membership.GetUser();
var currency = MemoryCacher.GetValue(string.Format("{0}:currency", windowsUser.ProviderUserKey));
if (currency != null && !string.IsNullOrEmpty(currency.ToString()))
return currency.ToString();
var currencyCode = "EUR"; // TODO change this get from our customer repo etc...
if (string.IsNullOrEmpty(currencyCode))
throw new InvalidOperationException("No Default Currency");
MemoryCacher.Add(
string.Format("{0}:currency", context.Request.AnonymousID),
gmgUser.CurrencyCode,
new DateTimeOffset(DateTime.Now.AddDays(1)));
return new Currency(currencyCode);
}
}

The last part of the puzzle is to configure structure map.

 container.For<SiteContext>().Use(ctx => new CustomSiteContext());

Jon D Jones

Software Architect, Programmer and Technologist Jon Jones is founder and CEO of London-based tech firm Digital Prompt. He has been working in the field for nearly a decade, specializing in new technologies and technical solution research in the web business. A passionate blogger by heart , speaker & consultant from England.. always on the hunt for the next challenge

More Posts

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *