public static bool ValidateApiKey(string accountNameKey, string apiKey) //, string loggingLabel = null, string loggingDetails = null) { var result = false; List <string> apiKeyStrings = null; string localCacheKey = accountNameKey + ":apiKeys"; #region (Plan A) Get list of api strings from local cache try { apiKeyStrings = (List <string>)HttpRuntime.Cache[localCacheKey]; } catch (Exception e) { } #endregion if (apiKeyStrings == null) { #region (Plan B) Get List of API strings from API Cache IDatabase cache = CoreServices.RedisConnectionMultiplexers.RedisMultiplexer.GetDatabase(); string hashApiKey = accountNameKey + ":apicache"; string hashApiField = "apikeys"; try { var redisApiValue = cache.HashGet(hashApiKey, hashApiField); if (redisApiValue.HasValue) { apiKeyStrings = JsonConvert.DeserializeObject <List <string> >(redisApiValue); } } catch { } #endregion if (apiKeyStrings == null) { List <ApiKeyModel> apiKeys = null; #region (Plan C) Get list of API keys from Redis Cache try { string hashMainKey = accountNameKey + ":apikeys"; string hashMainField = "list"; try { var redisValue = cache.HashGet(hashMainKey, hashMainField); if (redisValue.HasValue) { apiKeys = JsonConvert.DeserializeObject <List <ApiKeyModel> >(redisValue); } } catch { } } catch (Exception e) { var error = e.Message; //TODO: Log: error message for Redis call } #endregion if (apiKeys == null) { #region (Plan D) Get list of API keys from WCF var applicationApiKeysServiceClient = new ApplicationApiKeysService.ApplicationApiKeysServiceClient(); try { applicationApiKeysServiceClient.Open(); apiKeys = applicationApiKeysServiceClient.GetApiKeys(accountNameKey, Common.SharedClientKey).ToList(); WCFManager.CloseConnection(applicationApiKeysServiceClient); } 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(applicationApiKeysServiceClient, exceptionMessage, currentMethodString); #endregion } #endregion } //Convert to list of strings apiKeyStrings = new List <string>(); foreach (var key in apiKeys) { apiKeyStrings.Add(key.ApiKey.ToString()); } //Cache into API specific cache try { cache.HashSet(hashApiKey, hashApiField, JsonConvert.SerializeObject(apiKeyStrings), When.Always, CommandFlags.FireAndForget); } catch { } } //Cache locally HttpRuntime.Cache.Insert(localCacheKey, apiKeyStrings, null, DateTime.Now.AddMinutes(Common.ApiKeysCacheTimeInMinutes), TimeSpan.Zero); } if (apiKeyStrings != null) { if (apiKeyStrings.Contains(apiKey.ToLower())) { result = true; #region LOG USE OF API KEY HERE #endregion } return(result); } else { return(result); } }
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); }
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); //GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); System.Net.ServicePointManager.DefaultConnectionLimit = 12 * Environment.ProcessorCount; //<-- Allows us to marshal up more SearchService/SearchIndex Clients to avoid exhausting sockets. //Initialize Local Environment EnvironmentSettings.CurrentEnvironment.Site = WebConfigurationManager.AppSettings["Environment"]; //Require HTTPS if on stage or production: if (EnvironmentSettings.CurrentEnvironment.Site.ToLower() == "stage" || EnvironmentSettings.CurrentEnvironment.Site.ToLower() == "production" || EnvironmentSettings.CurrentEnvironment.Site.ToLower() == "release" || EnvironmentSettings.CurrentEnvironment.Site.ToLower() == "staging") { GlobalFilters.Filters.Add(new RequireHttpsAttribute()); } //Initialize Shared Client Key for WCF Calls Common.SharedClientKey = ConfigurationManager.AppSettings["SharedClientKey"]; #region Communicate with CoreServices and get static settings for this client to work with //Each client can get necessary settings and endpoint information from CoreServices for each enviornment. //This happens when the appliation is first initialized, and is stored in a static class for performance //If CoreServices are updated, a restart of each client may be necessary to get updated settings var platformSettingsServiceClient = new PlatformSettingsService.PlatformSettingsServiceClient(); // <-- We only use PlatformSettingsServiceClient in EnviornmentSettings because it is ONLY used at application startup: //Get & Initialize Settings from CoreServices: try { // PLATFORM SETTINGS SERVICE -------------------------------------- platformSettingsServiceClient.Open(); var platformSettingsResult = platformSettingsServiceClient.GetCorePlatformSettings(Common.SharedClientKey); CoreServices.PlatformSettings = platformSettingsResult; EnvironmentSettings.CurrentEnvironment.CoreServices = platformSettingsResult.Environment.Current; // CONFIGURE REDIS CONNECTIONS -------------- // Because the ConnectionMultiplexer does a lot, it is designed to be shared and reused between callers. // You should not create a ConnectionMultiplexer per operation. It is fully thread-safe and ready for this usage. // In all the subsequent examples it will be assumed that you have a ConnectionMultiplexer instance stored away for re-use. CoreServices.RedisConnectionMultiplexers.RedisMultiplexer = ConnectionMultiplexer.Connect(platformSettingsResult.Redis.Unsecure); //CoreServices.RedisConnectionMultiplexers.PlatformManager_Multiplexer = ConnectionMultiplexer.Connect(platformSettingsResult.Redis.PlatformManager_Unsecure); //CoreServices.RedisConnectionMultiplexers.AccountManager_Multiplexer = ConnectionMultiplexer.Connect(platformSettingsResult.Redis.AccountManager_Unsecure); // CONFIGURE SEARCH CONNECTIONS ---------- (Moved to search partitions) /* * CoreServices.SearchServiceQueryClient = new Microsoft.Azure.Search.SearchServiceClient( * platformSettingsResult.Search.SearchServiceName, * new Microsoft.Azure.Search.SearchCredentials( * platformSettingsResult.Search.ClientQueryKey * ) * );*/ // CONFIGURE DOCUMENT DATABSE CONNECTIONS using READ ONLY keys ------------- /* NOT USED BY API ANY LONGER - SEARCH ONLY * ConnectionPolicy _connectionPolicy = new ConnectionPolicy * { * //Since we are running within Azure we use Direct/TCP connections for performance. * //Web clients can alo use this. * //External clients like mobile phones that have ReadOnly Keys should use Gateway/Https * ConnectionMode = ConnectionMode.Direct, * ConnectionProtocol = Protocol.Tcp * }; * * CoreServices.DocumentDatabases.Accounts_DocumentClient = new Microsoft.Azure.Documents.Client.DocumentClient( * new Uri(platformSettingsResult.DocumentDB.AccountPartitionsReadOnlyAccountName), * platformSettingsResult.DocumentDB.AccountPartitionsReadOnlyAccountKey, * _connectionPolicy * ); * CoreServices.DocumentDatabases.Accounts_DocumentClient.OpenAsync(); */ //Close the connections WCFManager.CloseConnection(platformSettingsServiceClient); //<--Opens on init only } 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 connections & manage the exceptions WCFManager.CloseConnection(platformSettingsServiceClient, exceptionMessage, currentMethodString); #endregion platformSettingsServiceClient.Close(); EnvironmentSettings.CurrentEnvironment.CoreServices = "error: " + exceptionMessage; } #endregion //Force ALL results as JSON GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear(); //Register bundles last so options can be set by environment settings: BundleConfig.RegisterBundles(BundleTable.Bundles); }