/// <summary> /// Retrieves a setting /// </summary> /// <param name="services">The collection of lookup services</param> /// <param name="name">The name of the setting to retrieve</param> /// <param name="defaultValue">If the setting is not found, or there is an error retrieving the setting, this will be returned instead</param> /// <returns>The string setting (If you need to convert to something else, that will be done outside this call)</returns> public static string Get(ILookupServices <T, TS> services, string name, string defaultValue) => SafeTry.IgnoreException( () => { var service = services.Service; if (service.Key == null) { return(defaultValue); } var cachingSeconds = CachingSeconds(service); // Get the collection of settings inside a Lock (this is possibly recursive, so can't use semaphore locking) var settingsCollection = NamedLocker.Lock($"{service.Key}_Locker", num => num > 1 ? null // If recursive (will be allowed in lock again), the default value will be used instead of a real lookup : GetItems(cachingSeconds, service, services.Cache)); // If the above failed to find anything (eg. no settings, or a recursive call) if (settingsCollection.IsDefault()) { return(defaultValue); } // Return the setting value (or default if no setting exists) var setting = service.GetItem(settingsCollection, name); return(setting.IsDefault() ? defaultValue : service.GetValue(setting)); }, defaultValue );
/// <inheritdoc /> /// <summary> /// Attempts to retrieve an item from cache. /// If not found in cache, will make callback to obtain the item from the caller which will be stored for later use /// </summary> /// <typeparam name="T">The type of item</typeparam> /// <param name="key">Name of the item in cache</param> /// <param name="method">The callback function returning the item if not initially found in cache</param> /// <returns>The object from cache/callback function</returns> public virtual T Get <T>(string key, Func <T> method) { if (Get(key, out T item)) { return(item); } return(NamedLocker.Lock(key, num => { if (Get(key, out item)) { return item; } item = method(); if (Options.DoNotCacheDefault && item.IsDefault()) { return item; } // Also handles nulls, in case DoNotCacheDefault = false if (Options.DoNotCacheEmptyList && item is IEnumerable e && !e.GetEnumerator().MoveNext()) { return item; } Set(key, item); return item; }));
private void SetOrder() { if (Order != null) { return; } // Get the prefix string from the request Order = SafeTry.IgnoreException(() => Info.LogOrderPrefix) ?? ""; // Each request will increment this request property const string key = "logging_order"; // I don't think this lock is really necessary, as most everything will occur on main thread so this will be synchronous. // But leaving lock in case a thread is trying to log something Order += NamedLocker.Lock($"{key}_{Info.RequestId}", num => Info.LoggingOrder++); }