Skip to main content
Bounty Ended with 50 reputation awarded by Martin Davies
Corrected answer (old stuff was from Sitecore 6) and added direct answer to the last question
Source Link
Søren Kruse
  • 3.3k
  • 1
  • 17
  • 22

Short answer

In general they all seem to be using Sitecore.Context.Items underneath to store the state, which would make them all request-scoped, being dependent on the current HttpContext.

When HttpContext.Current is null thena static Sitecore.ContextCaching.Items falls back to using thread local storage. So without an HttpContextItemsContext they become thread-scopedobject.

(I'm not 100% confident on all this threading stuff, so anyone please correct me if I'm wrong)

Detailed answer

Most of the switchers/disablers inherit from Sitecore.Common.Switcher<TValue, TSwitchType>ItemsContext class, which uses the curret Sitecore.Context.ItemsHttpContext to store the stateif it's available (as a stack of the switched values, in case it's used multiple timesmaking it request-scoped).

Sitecore.Context.Items under the covers uses either HttpContext.Current.Items or if that isotherwise a nullprivate static IDictionary then falls back tomarked with the Sitecore.Threading.ThreadData.GetData("sc_items")[ThreadStatic] attribute (thread local storagemaking it thread-scoped).

namespacepublic Sitecore.Threadingclass ItemsContext : IDictionary, ICollection, IEnumerable
{
    public[ThreadStatic]
 class ThreadData  private static IDictionary dictionary;

    {protected virtual IDictionary Dictionary
    {
    public static object GetData(string key)get
        {
            LocalDataStoreSlotHttpContext namedDataSlotcurrent = ThreadHttpContext.GetNamedDataSlot(key);Current;
            if (namedDataSlotcurrent != null)
                return Threadcurrent.GetData(namedDataSlot);Items;
            return ItemsContext.dictionary ?? (objectItemsContext.dictionary = (IDictionary) null;new Hashtable());
        }
 
    }

    public static void SetData(string key, object data)
   this[string key]
    {
         get { return Thread.SetData(Threadthis.GetNamedDataSlotDictionary[(keyobject) ?? Thread.AllocateNamedDataSlot(key),key]; data);}
        }

set { this.Dictionary[(object) key] = value; }
  public class Keys}
  
    // ...
}

If they are thread specific, then what advice is there for using them in a multi-threaded scenario? In a parallel loop, should I create the switchers/disablers inside each 'iteration'?

When running things in parallel using Parallel.Foreach you would have to use the switcher/disabler inside the loop as they run on separate threads.

Parallel.ForEach(source, x =>
{
       using (new SecurityDisabler())
   public const{
 string Items = "sc_items";
    // Run your code }here
    }
});

##ExamplesAs Mark Cassidy also mentions in most cases I don't think there would be much or any gain in running stuff in parallel when accessing anything related to the Sitecore context as you would most likely be I/O limited anyway.

There might be a few usecases where it could make sense, but generally I probably would recommend against it.

Some more background info

Most of types inheritingthe switchers/disablers inherit from Sitecore.Common.Switcher<TValue, TSwitchType>: class, which uses Sitecore.Context.Items to store the state (as a stack of the switched values, in case it's used multiple times).

Some other types uses a custom implementation and just inherits IDisposable.

Examples of types inheriting Switcher<TValue, TSwitchType>:

##Examples of custom implementations only inheriting IDisposable:

Examples of custom implementations only inheriting IDisposable:

Short answer

In general they all seem to be using Sitecore.Context.Items underneath to store the state, which would make them all request-scoped, being dependent on the current HttpContext.

When HttpContext.Current is null then Sitecore.Context.Items falls back to using thread local storage. So without an HttpContext they become thread-scoped.

(I'm not 100% confident on all this threading stuff, so anyone please correct me if I'm wrong)

Detailed answer

Most of the switchers/disablers inherit from Sitecore.Common.Switcher<TValue, TSwitchType> class, which uses Sitecore.Context.Items to store the state (as a stack of the switched values, in case it's used multiple times).

Sitecore.Context.Items under the covers uses either HttpContext.Current.Items or if that is null then falls back to Sitecore.Threading.ThreadData.GetData("sc_items") (thread local storage).

namespace Sitecore.Threading
{
    public class ThreadData
    {
        public static object GetData(string key)
        {
            LocalDataStoreSlot namedDataSlot = Thread.GetNamedDataSlot(key);
            if (namedDataSlot != null)
                return Thread.GetData(namedDataSlot);
            return (object) null;
        }
 
        public static void SetData(string key, object data)
        {
            Thread.SetData(Thread.GetNamedDataSlot(key) ?? Thread.AllocateNamedDataSlot(key), data);
        }

        public class Keys
        {
            public const string Items = "sc_items";
        }
    }
}

##Examples of types inheriting Switcher<TValue, TSwitchType>:

##Examples of custom implementations only inheriting IDisposable:

In general they all seem to be using Sitecore.Context.Items which is a static Sitecore.Caching.ItemsContext object.

ItemsContext uses the curret HttpContext if it's available (making it request-scoped) or otherwise a private static IDictionary marked with the [ThreadStatic] attribute (making it thread-scoped).

public class ItemsContext : IDictionary, ICollection, IEnumerable
{
    [ThreadStatic]
    private static IDictionary dictionary;

    protected virtual IDictionary Dictionary
    {
        get
        {
            HttpContext current = HttpContext.Current;
            if (current != null)
                return current.Items;
            return ItemsContext.dictionary ?? (ItemsContext.dictionary = (IDictionary) new Hashtable());
        }
    }

    public object this[string key]
    {
        get { return this.Dictionary[(object) key]; }
        set { this.Dictionary[(object) key] = value; }
    }
 
    // ...
}

If they are thread specific, then what advice is there for using them in a multi-threaded scenario? In a parallel loop, should I create the switchers/disablers inside each 'iteration'?

When running things in parallel using Parallel.Foreach you would have to use the switcher/disabler inside the loop as they run on separate threads.

Parallel.ForEach(source, x =>
{
    using (new SecurityDisabler())
    {
        // Run your code here
    }
});

As Mark Cassidy also mentions in most cases I don't think there would be much or any gain in running stuff in parallel when accessing anything related to the Sitecore context as you would most likely be I/O limited anyway.

There might be a few usecases where it could make sense, but generally I probably would recommend against it.

Some more background info

Most of the switchers/disablers inherit from Sitecore.Common.Switcher<TValue, TSwitchType> class, which uses Sitecore.Context.Items to store the state (as a stack of the switched values, in case it's used multiple times).

Some other types uses a custom implementation and just inherits IDisposable.

Examples of types inheriting Switcher<TValue, TSwitchType>:

Examples of custom implementations only inheriting IDisposable:

Source Link
Søren Kruse
  • 3.3k
  • 1
  • 17
  • 22

Short answer

In general they all seem to be using Sitecore.Context.Items underneath to store the state, which would make them all request-scoped, being dependent on the current HttpContext.

When HttpContext.Current is null then Sitecore.Context.Items falls back to using thread local storage. So without an HttpContext they become thread-scoped.

(I'm not 100% confident on all this threading stuff, so anyone please correct me if I'm wrong)

Detailed answer

Most of the switchers/disablers inherit from Sitecore.Common.Switcher<TValue, TSwitchType> class, which uses Sitecore.Context.Items to store the state (as a stack of the switched values, in case it's used multiple times).

Sitecore.Context.Items under the covers uses either HttpContext.Current.Items or if that is null then falls back to Sitecore.Threading.ThreadData.GetData("sc_items") (thread local storage).

namespace Sitecore.Threading
{
    public class ThreadData
    {
        public static object GetData(string key)
        {
            LocalDataStoreSlot namedDataSlot = Thread.GetNamedDataSlot(key);
            if (namedDataSlot != null)
                return Thread.GetData(namedDataSlot);
            return (object) null;
        }

        public static void SetData(string key, object data)
        {
            Thread.SetData(Thread.GetNamedDataSlot(key) ?? Thread.AllocateNamedDataSlot(key), data);
        }

        public class Keys
        {
            public const string Items = "sc_items";
        }
    }
}

##Examples of types inheriting Switcher<TValue, TSwitchType>:

  • AuthenticationSwitcher
  • ContextItemSwitcher
  • EventDisabler
  • LinkDisbabler
  • LinkProviderSwitcher
  • LockingDisabler
  • SettingsSwitcher
  • TrackerSwitcher
  • SecurityDisabler
  • SiteContextSwitcher
  • And many more...

##Examples of custom implementations only inheriting IDisposable:

  • BulkUpdateContext (Uses locking, internal state and also Sitecore.Context.Items)
  • LanguageSwitcher (Uses Sitecore.Context.SetLanguage())