<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by David Ketnor</title><link href="http://world.optimizely.com" /><updated>2014-08-12T17:09:34.0000000Z</updated><id>https://world.optimizely.com/blogs/David-Ketnor/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>ICurrentMarket Storage Providers</title><link href="https://world.optimizely.com/blogs/David-Ketnor/Dates/2014/8/ICurrentMarket-Storage-Providers/" /><id>&lt;p&gt;This is my first ever blog post, so be gentle ;)&lt;/p&gt;  &lt;p&gt;In this post we’re going to discuss how we can create a number of different storage provider’s for use with our ICurrentMarket implementation. The main objectives for this post will be to: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Provide implementations for a number of different storage providers, including Session, Profile, Cookie &lt;/li&gt;    &lt;li&gt;Highlight how clean, well architected code will allow your implementation to serve numerous clients and provide more extensible solutions &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;So without further ado, we’ll get started.&lt;/p&gt;  &lt;h3&gt;ICurrentMarket&lt;/h3&gt;  &lt;p&gt;The purpose of this interface is to return the market of the current request as detailed &lt;a href=&quot;http://world.episerver.com/Documentation/Items/Developers-Guide/EPiServer-Commerce/75/Markets/Markets/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Here is a typical implementation taken from the commerce demo site, which persists the users current market within their membership profile.&lt;/p&gt;  &lt;pre style=&quot;width: 100%&quot;&gt;namespace EPiServer.Commerce.Sample.Helpers
{
    /// &lt;summary&gt;
    /// Implementation of current market selection that stores information in user profile.
    /// &lt;/summary&gt;
    public class MarketStorage : ICurrentMarket
    {
        private const string _marketIdKey = &amp;quot;MarketId&amp;quot;;
        private readonly IMarketService _marketService;
 
        /// &lt;summary&gt;
        /// Initializes a new instance of the &lt;see cref=&quot;MarketStorage&quot; /&gt; class.
        /// &lt;/summary&gt;
        public MarketStorage()
            : this(ServiceLocation.ServiceLocator.Current.GetInstance&lt;imarketservice&gt;())
        { }
 
        /// &lt;summary&gt;
        /// Initializes a new instance of the &lt;see cref=&quot;MarketStorage&quot; /&gt; class.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;marketService&quot; /&gt;The market service.
        public MarketStorage(IMarketService marketService)
        {
            _marketService = marketService;
        }
 
        /// &lt;summary&gt;
        /// Gets the &lt;see cref=&quot;IMarket&quot; /&gt; selected in the current user profile, if the value is
        /// set and the indicated market is valid; ; otherwise, gets the default &lt;see cref=&quot;IMarket&quot; /&gt;.
        /// &lt;/summary&gt;
        /// &lt;returns&gt;The current &lt;see cref=&quot;IMarket&quot; /&gt;.&lt;/returns&gt;
        public IMarket GetCurrentMarket()
        {
            var profileStorage = GetProfileStorage();
            var profileMarketId = profileStorage == null ? null : profileStorage[_marketIdKey] as string;
            var marketId = string.IsNullOrEmpty(profileMarketId) ? MarketId.Default : new MarketId(profileMarketId);
            var market = _marketService.GetMarket(marketId);
 
            if (market == null &amp;amp;&amp;amp; marketId != MarketId.Default)
            {
                market = _marketService.GetMarket(MarketId.Default);
            }
 
            UpdateProfile(market);
 
            return market;
        }
 
        /// &lt;summary&gt;
        /// Sets the current market, if &lt;paramref name=&quot;marketId&quot; /&gt; represents a valid market;
        /// otherwise, performs no action.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;marketId&quot; /&gt;The market id.
        /// &lt;remarks&gt;This will also set the current currency for the ECF context.&lt;/remarks&gt;
        public void SetCurrentMarket(MarketId marketId)
        {
            var market = _marketService.GetMarket(marketId);
            if (market != null)
            {
                UpdateProfile(market);
                SiteContext.Current.Currency = market.DefaultCurrency;
                Globalization.ContentLanguage.PreferredCulture = market.DefaultLanguage;
            }
        }
 
        private void UpdateProfile(IMarket market)
        {
            var profileStorage = GetProfileStorage();
            if (profileStorage != null)
            {
                var originalMarketId = profileStorage[_marketIdKey] as string;
                var currentMarketId = market == null || market.MarketId == MarketId.Default ? string.Empty : market.MarketId.Value;
                if (!string.Equals(originalMarketId, currentMarketId, StringComparison.Ordinal))
                {
                    profileStorage[_marketIdKey] = currentMarketId;
                    profileStorage.Save();
                }
            }
        }
 
        private ProfileBase GetProfileStorage()
        {
            var httpContext = HttpContext.Current;
            return httpContext == null ? null : httpContext.Profile;
        }
    }
}&lt;/imarketservice&gt;&lt;/pre&gt;

&lt;p&gt;This works well, but includes the underlying persistence within the actual implementation of ICurrentMarket. If we had further clients who had different persistence requirements, we need to implement ICurrentMarket again which would result in repeated ICurrentMarket implementations (&lt;a href=&quot;http://en.wikipedia.org/wiki/Don&#39;t_repeat_yourself&quot;&gt;DRY&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;If we abstracted the Current Market storage implementation out of ICurrentMarket we’d be in a better place.&lt;/p&gt;

&lt;p&gt;Enter ICurrentMarketStorageProvider&lt;/p&gt;

&lt;h3&gt;ICurrentMarketStorageProvider&lt;/h3&gt;

&lt;p&gt;The purpose of this interface is to and store and retrieve the current market. &lt;/p&gt;

&lt;pre style=&quot;width: 100%&quot;&gt;public interface ICurrentMarketStorageProvider
    {
        string MarketIdKey { get; }
 
        string Get();
 
        void Set(string value);
    }&lt;/pre&gt;

&lt;p&gt;This is a pretty simple implementation, so how does it change our implementation of ICurrentMarket?&lt;/p&gt;

&lt;pre style=&quot;width: 100%&quot;&gt;/// &lt;summary&gt;
    /// Implementation of current market selection.
    /// &lt;/summary&gt;
    public class SiteCurrentMarket : ICurrentMarket
    {
        private readonly IMarketService marketService;
        private readonly ICurrentMarketStorageProvider storageProvider;
 
        /// &lt;summary&gt;
        /// Initializes a new instance of the &lt;see cref=&quot;SiteCurrentMarket&quot; /&gt; class.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;marketService&quot; /&gt;The market service.
        /// &lt;param name=&quot;storageProvider&quot; /&gt;The market storage provider
        public SiteCurrentMarket(IMarketService marketService, ICurrentMarketStorageProvider storageProvider)
        {
            this.marketService = marketService;
            this.storageProvider = storageProvider;
        }
 
        /// &lt;summary&gt;
        /// Gets the &lt;see cref=&quot;IMarket&quot; /&gt; selected within the storage provider, if the value is
        /// set and the indicated market is valid; ; otherwise, gets the default &lt;see cref=&quot;IMarket&quot; /&gt;.
        /// &lt;/summary&gt;
        /// &lt;returns&gt;The current &lt;see cref=&quot;IMarket&quot; /&gt;.&lt;/returns&gt;
        public IMarket GetCurrentMarket()
        {
            string currentMarketId;
 
            try
            {
                currentMarketId = this.storageProvider.Get();
            }
            catch (Exception ex)
            {
                currentMarketId =  MarketId.Default;
            }
 
            var marketId = string.IsNullOrEmpty(currentMarketId) ? MarketId.Default : new MarketId(currentMarketId);
            var market = this.marketService.GetMarket(marketId);
 
            if (market == null &amp;amp;&amp;amp; marketId != MarketId.Default)
            {
                market = this.marketService.GetMarket(MarketId.Default);
            }
 
            return market;
        }
 
        /// &lt;summary&gt;
        /// Sets the current market, if &lt;paramref name=&quot;marketId&quot; /&gt; represents a valid market;
        /// otherwise, performs no action.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;marketId&quot; /&gt;The market id.
        /// &lt;remarks&gt;This will also set the current currency for the ECF context.&lt;/remarks&gt;
        public void SetCurrentMarket(MarketId marketId)
        {
            var market = this.marketService.GetMarket(marketId);
            if (market != null)
            {
                this.storageProvider.Set(market.MarketId.Value);
                SiteContext.Current.Currency = market.DefaultCurrency;
                EPiServer.Globalization.ContentLanguage.PreferredCulture = market.DefaultLanguage;
            }
            else
            {
                throw new ArgumentException(&amp;quot;Unknown MarketId when setting Current Market&amp;quot;, &amp;quot;marketId&amp;quot;);
            }
        }
    }&lt;/pre&gt;

&lt;p&gt;Note the ICurrentMarketStorageProvider interface being passed as a constructor parameter and also note the implementations of GetCurrentMarket() and SetCurrentMarket() now use the storage provider to retrieve and persist the current market. Now that we’ve abstracted the persistence out of ICurrentMarket lets implement some example storage providers.&lt;/p&gt;

&lt;h3&gt;MembershipCurrentMarketStorageProvider&lt;/h3&gt;

&lt;pre style=&quot;width: 100%&quot;&gt;using System;
    using System.Web;
    using System.Web.Profile;
 
    /// &lt;summary&gt;
    /// A membership based provider for storing a users current market.
    /// &lt;/summary&gt;
    public class MembershipCurrentMarketStorageProvider : ICurrentMarketStorageProvider
    {
        private readonly HttpContextBase context;
 
        public HttpContextBase Context
        {
            get
            {
                return context;
            }
        }
 
        public virtual string MarketIdKey
        {
            get
            {
                return &amp;quot;MarketId&amp;quot;;
            }
        }
 
        public MembershipCurrentMarketStorageProvider()
        {
            this.context = new HttpContextWrapper(HttpContext.Current);
        }
 
        public MembershipCurrentMarketStorageProvider(HttpContextBase context)
        {
            this.context = context;
        }
 
        public virtual string Get()
        {
            var profileMarketId = string.Empty;
 
            if (context != null &amp;amp;&amp;amp; context.Profile != null)
            {
                if (context.Profile.GetPropertyValue(this.MarketIdKey) != null)
                {
                    profileMarketId = context.Profile[this.MarketIdKey] as string;
                }
            }
 
            return profileMarketId;
        }
 
        public virtual void Set(string value)
        {
            if (context != null &amp;amp;&amp;amp; context.Profile != null)
            {
                var originalMarketId = context.Profile[this.MarketIdKey] as string;
                if (!string.Equals(originalMarketId, value, StringComparison.Ordinal))
                {
                    context.Profile[this.MarketIdKey] = value;
                    context.Profile.Save();
                }
            }
        }
    }&lt;/pre&gt;

&lt;p&gt;This is pretty simple and is more or less a simple refactoring of the original MarketStorage example above. &lt;/p&gt;

&lt;h3&gt;SessionCurrentMarketProvider&lt;/h3&gt;

&lt;pre style=&quot;width: 100%&quot;&gt;using System.Web;
 
    /// &lt;summary&gt;
    /// A session based provider for storing a users current market.
    /// &lt;/summary&gt;
    public class SessionCurrentMarketStorageProvider : ICurrentMarketStorageProvider
    {
        private readonly HttpSessionStateBase session;
 
        public HttpSessionStateBase Session
        {
            get
            {
                return session;
            }
        }
 
        public virtual string MarketIdKey
        {
            get
            {
                return &amp;quot;MarketId&amp;quot;;
            }
        }
 
        public SessionCurrentMarketStorageProvider()
        {
            this.session = new HttpSessionStateWrapper(HttpContext.Current.Session);
        }
 
        public SessionCurrentMarketStorageProvider(HttpSessionStateBase session)
        {
            this.session = session;
        }
 
        public string Get()
        {
            if (Session != null &amp;amp;&amp;amp; Session[this.MarketIdKey] != null)
            {
                return Session[this.MarketIdKey].ToString();
            }
            
            return string.Empty;
        }
 
        public void Set(string value)
        {
            if (Session != null)
            {
                Session[this.MarketIdKey] = value;
            }
        }
    }&lt;/pre&gt;

&lt;p&gt;Again another simple implementation, that utilises Http session. &lt;/p&gt;

&lt;p&gt;&lt;b&gt;NOTE:&lt;/b&gt; If you’re thinking of using this within production environments that are load balanced ensure server affinity is configured accordingly or you use permanent session storage techniques such as SQL Server or a State Server. &lt;/p&gt;

&lt;h3&gt;CookieCurrentMarketStorageProvider &lt;/h3&gt;

&lt;pre style=&quot;width: 100%&quot;&gt;using System;
    using System.Web;
 
    /// &lt;summary&gt;
    /// A cookie based provider for storing a users current market.
    /// &lt;/summary&gt;
    public class CookieCurrentMarketStorageProvider : ICurrentMarketStorageProvider
    {
        private readonly HttpContextBase context;
 
        public HttpContextBase Context
        {
            get
            {
                return this.context;
            }
        }
 
        public virtual string CookieName
        {
            get
            {
                return &amp;quot;Market&amp;quot;;
            }
        }
 
        public virtual string MarketIdKey
        {
            get
            {
                return &amp;quot;MarketId&amp;quot;;
            }
        }
 
        public virtual bool StoreAsSecureCookie
        {
            get
            {
                return false;
            }
        }
 
        public CookieCurrentMarketStorageProvider()
        {
            this.context = new HttpContextWrapper(HttpContext.Current);
        }
 
        public CookieCurrentMarketStorageProvider(HttpContextBase context)
        {
            this.context = context;
        }
 
        public virtual string Get()
        {
            if (this.Context != null)
            {
                var httpCookie = this.Context.Request.Cookies[this.CookieName];
                if (httpCookie != null)
                {
                    return httpCookie[this.MarketIdKey];
                }
            }
 
            return string.Empty;
        }
 
        public virtual void Set(string value)
        {
            if (this.Context != null)
            {
                var httpCookie = this.context.Request.Cookies[this.CookieName] ?? new HttpCookie(this.CookieName);
 
                httpCookie[this.MarketIdKey] = value;
                httpCookie.Expires = DateTime.Now.AddHours(2d);
                httpCookie.Secure = this.StoreAsSecureCookie;
                context.Response.Cookies.Set(httpCookie);
            }
        }
    }&lt;/pre&gt;

&lt;p&gt;Another fairly standard implementation.&lt;/p&gt;

&lt;h3&gt;Configuration&lt;/h3&gt;

&lt;p&gt;The only thing we need to do now is register the implementation within our &lt;b&gt;IConfigurableModule&lt;/b&gt; and we’re away.&lt;/p&gt;

&lt;p&gt;A point worth mentioning is that whenever you use a Storage Provider which utilises the HttpContext ensure that ICurrentMarketStorageProvider and ICurrentMarket are scoped accordingly.&lt;/p&gt;

&lt;h2&gt;In Summary&lt;/h2&gt;

&lt;p&gt;This approach allows your implementation of ICurrentMarket to remain unchanged across multiple clients/persistence requirements and allows your persistance mechanism to be interchangeable. This also provides the benefit of allowing your ICurrentMarket and your storage providers to be all testable. &lt;/p&gt;

&lt;p&gt;So there you go… a pretty fundamental blog post which should hopefully highlight how small architectural changes can provide big benefits further down the line.&lt;/p&gt;

&lt;p&gt;Thanks for reading&lt;/p&gt;</id><updated>2014-08-12T17:09:34.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>