Sitecore.Analytics.Tracker.Current is null when invoked through a pipeline

1.1k Views Asked by At

I need to redirect based on the country location the user is trying to access. For example when user trying to access http://www.example.com/ from china my site should as http://www.example.com/zh. I am checking using the sitecore tracker in pipeline process to get the country code using the below method.

public void Process(HttpRequestArgs args)
    {
        Assert.ArgumentNotNull(args, "args");

        if (HttpContext.Current == null
          || Context.Site == null
            ////TODO:       || Sitecore.Context.PageMode...
          || Context.Database == null || Context.Site.Name == "shell" || !this._sites.Contains(Context.Site.Name))
        {
            return;
        }

        // contains path including language and query string
        // (not anchor name), but not hostname.
        // We can use this to add the language back into the path.
        string rawPath = Sitecore.Context.RawUrl;

        if (!rawPath.StartsWith("/sitecore") && !rawPath.StartsWith("/" + Sitecore.Context.Language.Name + "/") && !rawPath.StartsWith("/" + Sitecore.Context.Language.Name) && !rawPath.StartsWith("/default.aspx"))
        {
            string langCode = "";

            if(!string.IsNullOrEmpty(GeoIPUtils.GetUserGeoIP()))
            {
                try
                {
                    string country = GeoIPUtils.GetUserGeoIP();;
                    if (country.Trim().ToUpper() == "China".ToUpper())
                        langCode = "zh";
                    else if (country.Trim().ToUpper() == "Japan".ToUpper())
                        langCode = "jp";
                    else if (country.Trim().ToUpper() == "Thailand".ToUpper())
                        langCode = "th";
                    else
                        langCode = "en";

                }
                catch(Exception)
                {
                    langCode = "en";
                }
            }
            else
            {

                langCode = HttpContext.Current.Request.Cookies["avc#lang"].Value.ToString();
            }

            if (!string.IsNullOrEmpty(langCode))
            {
                Language language = null;
                if (Language.TryParse(langCode, out language))
                {
                    //then try to get the language item id from the language or two letter iso code             
                    ID langID = LanguageManager.GetLanguageItemId(language, Sitecore.Context.Database);
                    if (!ID.IsNullOrEmpty(langID))
                    {
                        //sometimes the language found is slightly different than official language item used in SC                 
                        language = LanguageManager.GetLanguage(language.CultureInfo.TwoLetterISOLanguageName);

                        if (Context.Item != null)
                        {
                            List<string> availableLangs = LanguagesWithContent(Context.Item);
                            if (availableLangs != null && availableLangs.Count > 0 && !availableLangs.Contains(language.CultureInfo.TwoLetterISOLanguageName.ToString()))
                            {
                                langCode = availableLangs.FirstOrDefault().ToString();
                            }
                        }
                        else
                        {
                            langCode = "en";
                        }
                    }
                    else
                    {
                        langCode = "en";
                    }
                }
            }

            HttpContext.Current.Response.RedirectPermanent("/" + (String.IsNullOrEmpty(langCode) ? Sitecore.Context.Language.Name : langCode) + rawPath);

        }
    }

Below is the GetUserGeoIP function

public static string GetUserGeoIP()
    {
        string countryCode = "";
        try
        {
            countryCode = Sitecore.Analytics.Tracker.Current.Interaction.GeoData.Country;
        }
        catch(Exception ex)
        {
            Log.Error("GetUserGeoIP Error: " + ex.Message + " Source: " + ex.Source + " Stack Trace :" + ex.StackTrace + " Inner Ex : " + ex.InnerException, ex);
            countryCode = "GB";

        }

        if (!string.IsNullOrEmpty(countryCode))
        {
            var countryItem = ISO3166.FromAlpha2(countryCode);
            if (countryItem != null)
                return countryItem.Name;
        }

        return "Other";
    }

But I am getting an below exception

7904 10:43:25 ERROR Cannot create tracker.
Exception: System.InvalidOperationException
Message: session is not initialized
Source: Sitecore.Analytics
   at Sitecore.Analytics.Data.HttpSessionContextManager.GetSession()
   at Sitecore.Analytics.Pipelines.EnsureSessionContext.EnsureContext.Process(InitializeTrackerArgs args)
   at (Object , Object[] )
   at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
   at Sitecore.Analytics.DefaultTracker.EnsureSessionContext()
   at Sitecore.Analytics.Pipelines.CreateTracker.GetTracker.Process(CreateTrackerArgs args)
   at (Object , Object[] )
   at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
   at Sitecore.Analytics.Tracker.Initialize()

Note: The same GetUserGeoIP method is used in API which gets the correct countryName. I am using Sitecore.NET 8.0 (rev. 151127) version

Any help on this highly appreciated

1

There are 1 best solutions below

0
On

Your processor is probably too soon in the pipeline(s). You can find an overview of the request pipelines here: http://sitecoreskills.blogspot.be/2015/02/a-sitecore-8-request-from-beginning-to.html

You should put your processor after the tracker has been initialized and the geo data has been fetched. I did something similar a while ago and placed my processor in the startAnalytics pipeline.

Fetching the geo data is async so that might (will) give issues when doing this in the first request pipeline. Read this article to tackle that issue by calling UpdateGeoIpData with a timespan.