Exemple #1
0
        private static int LocalAccountCacheTimeInHours = 48; //<-- We cache the account locally for 2 days to avoid a Redis or WCF call on a hot account

        public static AccountManagementService.Account GetAccountObject(string accountNameKey)
        {
            AccountManagementService.Account account = null;

            #region (Plan A) Get Account from Local Cache

            bool   localCacheEmpty = false;
            string localCacheKey   = accountNameKey + ":account";

            try
            {
                account = (AccountManagementService.Account)HttpRuntime.Cache[localCacheKey];
            }
            catch (Exception e)
            {
                var error = e.Message;
                //TODO: Log: error message for local cache call
            }

            #endregion

            if (account == null)
            {
                localCacheEmpty = true;

                #region (Plan B) Get Account from Redis Cache

                try
                {
                    //First we attempt to get the account from the Redis Cache

                    IDatabase cache = CoreServices.RedisConnectionMultiplexers.RedisMultiplexer.GetDatabase();

                    string hashKey   = "accountbyname:" + accountNameKey;
                    string hashField = "model";

                    try
                    {
                        var redisValue = cache.HashGet(hashKey, hashField);
                        if (redisValue.HasValue)
                        {
                            account = JsonConvert.DeserializeObject <AccountManagementService.Account>(redisValue);
                        }
                    }
                    catch
                    {
                    }
                }
                catch (Exception e)
                {
                    var error = e.Message;
                }

                #endregion
            }
            if (account == null)
            {
                #region (Plan C) Get Account from WCF

                //If a failure occurs, or the redis cache is empty we get the user from the WCF service
                var accountManagementServiceClient = new AccountManagementService.AccountManagementServiceClient();

                try
                {
                    accountManagementServiceClient.Open();
                    account = accountManagementServiceClient.GetAccount(accountNameKey, Common.SharedClientKey);

                    //Close the connection
                    WCFManager.CloseConnection(accountManagementServiceClient);
                }
                catch (Exception e)
                {
                    #region Manage Exception

                    string exceptionMessage = e.Message.ToString();

                    var    currentMethod       = System.Reflection.MethodBase.GetCurrentMethod();
                    string currentMethodString = currentMethod.DeclaringType.FullName + "." + currentMethod.Name;

                    // Abort the connection & manage the exception
                    WCFManager.CloseConnection(accountManagementServiceClient, exceptionMessage, currentMethodString);

                    #endregion
                }

                #endregion
            }

            if (localCacheEmpty)
            {
                #region store Account into local cache

                //store string in local cache for a few moments:
                HttpRuntime.Cache.Insert(localCacheKey, account, null, DateTime.Now.AddHours(Common.LocalAccountCacheTimeInHours), TimeSpan.Zero);

                #endregion
            }

            return(account);
        }
Exemple #2
0
        public static Models.Search.SearchResults SearchProducts(AccountManagementService.Account account, string text, string filter = null, string orderBy = "relevance", int skip = 0, int top = 120, bool locationSort = false, string locationSortString = null, bool includeHidden = false)
        {
            if (top > 120)
            {
                //We do not ever allow more than 120 results per page in search
                top = 120;
            }

            //ProductResults productResults = null;
            //List<ProductDocumentModel> products = null;
            //dynamic products = null;
            DocumentSearchResult azuresearchresult = null;


            //Get from cache first
            var accountSearchIndex = Common.SearchIndexCache[account.ProductSearchIndex] as ISearchIndexClient;

            if (accountSearchIndex == null)
            {
                //Not in cache, create: ----------------------------

                //Get client for this accounts search index (Moved to partitioning)
                //var accountSearchIndex = CoreServices.SearchServiceQueryClient.Indexes.GetClient(account.ProductSearchIndex);

                //Get search partition for this account, create client and connect to index: =======================================================

                if (CoreServices.PlatformSettings.SearchParitions == null || CoreServices.PlatformSettings.SearchParitions.ToList().Count == 0)
                {
                    //No Search Partitions Available in Static List, refresh list from Core Services
                    Common.RefreshPlatformSettings();
                }

                var searchPartition = CoreServices.PlatformSettings.SearchParitions.FirstOrDefault(partition => partition.Name == account.SearchPartition);

                if (searchPartition == null)
                {
                    //May be a new partition, refresh platform setting and try again
                    Common.RefreshPlatformSettings();
                    searchPartition = CoreServices.PlatformSettings.SearchParitions.FirstOrDefault(partition => partition.Name == account.SearchPartition);
                }
                var searchServiceClient = new SearchServiceClient(searchPartition.Name, new SearchCredentials(searchPartition.Key));
                accountSearchIndex = searchServiceClient.Indexes.GetClient(account.ProductSearchIndex);

                //Store in cache: ---------------------
                Common.SearchIndexCache.Set(account.ProductSearchIndex, accountSearchIndex, new CacheItemPolicy {
                    AbsoluteExpiration = DateTimeOffset.UtcNow.AddMinutes(Common.SearchIndexClientCacheTimeInMinutes)
                });
            }



            //Prepare the query
            var searchParameters = new SearchParameters();

            if (includeHidden == false)
            {
                if (String.IsNullOrEmpty(filter))
                {
                    filter = "(visible eq true)";
                }
                else
                {
                    filter += " and (visible eq true)";
                }
            }

            //Assign filters
            searchParameters.Filter = filter;


            //Add location sorting first (always supercedes others) if applicable
            if (locationSort)
            {
                //include location sorting
                //if (locationSortType == "point")
                //{
                searchParameters.OrderBy.Add(locationSortString);
                //}
                //else if (locationSortType == "bounds")
                //{

                //}
            }



            searchParameters.Skip = skip;
            searchParameters.Top  = top;


            //We only add ordering and result count if we ask for MORE than 1 item back

            searchParameters.OrderBy = new List <string>();

            if (top > 1)
            {
                if (orderBy.ToLower() != "relevance")
                {
                    var orderByArray = orderBy.Split(',');

                    searchParameters.OrderBy.Add(orderBy);
                }

                searchParameters.IncludeTotalResultCount = true;
            }



            //build strings to search against:
            //TO DO:
            //

            bool listingImagesOnly = true;

            //bool includesLocationData = false; //<--If true we will need to merge location Metadata and remove Metadata field

            if (top == 1)
            {
                //This uses the Details Property Fields:

                //$select=categoryNameKey,categoryName,orderId,subcategoryName

                listingImagesOnly       = false;                                                             //<--Get all images for details
                searchParameters.Select = GetSearchFields(account.AccountNameKey, PropertyListType.Details); //<-- InOrder???
            }
            else
            {
                //This uses the Listings Property Fields:

                //$select=categoryNameKey,categoryName,orderId,subcategoryName
                searchParameters.Select = GetSearchFields(account.AccountNameKey, PropertyListType.Listings); //<-- InOrder???
            }



            //If the query contains dashes and no spaces, wrap it in quotes in order to get GUIDS and SKUS (The indexer replaces "-" with " " when storing into search)
            try
            {
                if (text.Contains("-"))
                {
                    if (!text.Contains(" "))
                    {
                        text = "\"" + text + "\"";
                    }
                }
            }
            catch
            {
            }

            //Perform the search
            //NOTE: We add a wildcard at the end to get better results from text searches
            azuresearchresult = accountSearchIndex.Documents.Search(text + "*", searchParameters);



            #region Loop through each search result, transform into SearchResult object and append associated 'Listing' type ImageRecords to each results

            var searchresults = new Models.Search.SearchResults();

            searchresults.Count    = azuresearchresult.Count;
            searchresults.Returned = azuresearchresult.Results.Count();

            if ((skip + top) >= azuresearchresult.Count)
            {
                searchresults.Remaining = 0;
            }
            else
            {
                searchresults.Remaining = Convert.ToInt32(azuresearchresult.Count) - (skip + top);
            }

            if (skip >= searchresults.Count)
            {
                searchresults.Range = null;
            }
            else if (searchresults.Returned == 0)
            {
                searchresults.Range = null;
            }
            else
            {
                searchresults.Range = (skip + 1) + "-" + (skip + searchresults.Returned);
            }

            searchresults.ContinuationToken = azuresearchresult.ContinuationToken;
            searchresults.Facets            = azuresearchresult.Facets;
            searchresults.Coverage          = azuresearchresult.Coverage;

            searchresults.Results = new List <Models.Search.Result>();

            foreach (Microsoft.Azure.Search.Models.SearchResult azureresult in azuresearchresult.Results)
            {
                var result = new Models.Search.Result();

                result.Score    = azureresult.Score;
                result.Document = azureresult.Document;
                //result.Images = new List<dynamic>();
                //result.Images = new System.Dynamic.ExpandoObject();

                result.Images = Dynamics.Images.BuildDynamicImagesListForJson(account.AccountNameKey, "product", azureresult.Document["id"].ToString(), listingImagesOnly);

                searchresults.Results.Add(result);
            }

            #endregion

            return(searchresults);
        }
Exemple #3
0
        public JsonNetResult ProductFacets(bool includeHidden = false)
        {
            ExecutionType executionType = ExecutionType.local;
            Stopwatch     stopWatch     = new Stopwatch();

            stopWatch.Start();

            //Get the subdomain (if exists) for the api call
            string accountNameKey = Common.GetSubDomain(Request.Url);

            if (String.IsNullOrEmpty(accountNameKey))
            {
                return(new JsonNetResult {
                    Data = "Not found"
                });                                              //return Request.CreateResponse(HttpStatusCode.NotFound);
            }

            AccountManagementService.Account account = Common.GetAccountObject(accountNameKey);

            string localCacheKey = accountNameKey + ":product:search:facets:includeHidden:" + includeHidden;


            List <ProductSearchFacet>     facets     = null;
            List <ProductSearchFacetJson> facetsJson = null;

            if (account == null)
            {
                return(new JsonNetResult {
                    Data = "Not found"
                });                                              //return Request.CreateResponse(HttpStatusCode.NotFound);
            }
            else
            {
                #region (Plan A) Get data from local cache

                try
                {
                    facetsJson = (List <ProductSearchFacetJson>)HttpRuntime.Cache[localCacheKey];
                }
                catch (Exception e)
                {
                    var error = e.Message;
                    //TODO: Log: error message for local cache call
                }

                #endregion

                if (facetsJson == null)
                {
                    #region (Plan B) Get Public json from second layer of Redis Cache

                    IDatabase cache = CoreServices.RedisConnectionMultiplexers.RedisMultiplexer.GetDatabase();

                    string pathAndQuery = Common.GetApiPathAndQuery(Request.Url);

                    string hashApiKey   = accountNameKey + ":apicache";
                    string hashApiField = pathAndQuery;

                    try
                    {
                        var redisApiValue = cache.HashGet(hashApiKey, hashApiField);

                        if (redisApiValue.HasValue)
                        {
                            facetsJson    = JsonConvert.DeserializeObject <List <ProductSearchFacetJson> >(redisApiValue);
                            executionType = ExecutionType.redis_secondary;
                        }
                    }
                    catch
                    {
                    }

                    #endregion

                    if (facetsJson == null)
                    {
                        #region (Plan C) Get data from Redis Cache

                        try
                        {
                            //Attempt to get facets from the Redis Cache

                            string hashKey   = accountNameKey + ":search";
                            string hashField = "facets:products:visible";

                            if (includeHidden)
                            {
                                hashField = "facets:products";
                            }

                            try
                            {
                                var redisValue = cache.HashGet(hashKey, hashField);

                                if (redisValue.HasValue)
                                {
                                    facets        = JsonConvert.DeserializeObject <List <ProductSearchFacet> >(redisValue);
                                    executionType = ExecutionType.redis_main;
                                }
                            }
                            catch
                            {
                            }
                        }
                        catch (Exception e)
                        {
                            var error = e.Message;
                            //Log error message for Redis call
                        }

                        #endregion

                        if (facets == null)
                        {
                            #region (Plan D) Get data from WCF

                            var applicationSearchServiceClient = new ApplicationSearchService.ApplicationSearchServiceClient();

                            try
                            {
                                applicationSearchServiceClient.Open();
                                facets = applicationSearchServiceClient.GetProductFacets(accountNameKey, includeHidden, Common.SharedClientKey).ToList();

                                //Close the connection
                                WCFManager.CloseConnection(applicationSearchServiceClient);

                                executionType = ExecutionType.wcf;
                            }
                            catch (Exception e)
                            {
                                #region Manage Exception

                                string exceptionMessage = e.Message.ToString();

                                var    currentMethod       = System.Reflection.MethodBase.GetCurrentMethod();
                                string currentMethodString = currentMethod.DeclaringType.FullName + "." + currentMethod.Name;

                                // Abort the connection & manage the exception
                                WCFManager.CloseConnection(applicationSearchServiceClient, exceptionMessage, currentMethodString);

                                #endregion
                            }

                            #endregion
                        }
                    }

                    #region  Transform into json object, & cache locally or locally and redisAPI layer

                    if (facetsJson != null)
                    {
                        //Just cache locally (we got json from the api redis layer)
                        HttpRuntime.Cache.Insert(localCacheKey, facetsJson, null, DateTime.Now.AddMinutes(Common.SearchFacetsCacheTimeInMinutes), TimeSpan.Zero);
                    }
                    else if (facets != null)
                    {
                        //Transform categories into JSON and cache BOTH locally AND into redis
                        facetsJson = Transforms.Json.SearchTransforms.ProductFacets(facets);
                        HttpRuntime.Cache.Insert(localCacheKey, facetsJson, null, DateTime.Now.AddMinutes(Common.SearchFacetsCacheTimeInMinutes), TimeSpan.Zero);

                        try
                        {
                            cache.HashSet(hashApiKey, hashApiField, JsonConvert.SerializeObject(facetsJson), When.Always, CommandFlags.FireAndForget);
                        }
                        catch
                        {
                        }
                    }

                    #endregion
                }
            }



            //Create results object
            ProductSearchFacetsJson facetsJsonResult = new ProductSearchFacetsJson();
            facetsJsonResult.facets = facetsJson;

            //Add execution data
            stopWatch.Stop();
            facetsJsonResult.executionType = executionType.ToString();
            facetsJsonResult.executionTime = stopWatch.Elapsed.TotalMilliseconds + "ms";

            JsonNetResult jsonNetResult = new JsonNetResult();
            jsonNetResult.Formatting = Newtonsoft.Json.Formatting.Indented;
            jsonNetResult.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local; //<-- Convert UTC times to LocalTime
            jsonNetResult.Data = facetsJsonResult;

            return(jsonNetResult);
        }