ASP.Net access enviroment variables in singleton class - c#

i need to access my enviroment variables from a singleton class.
I only found soulutions where the WebBuilder injects the configuration through the constructor or methods to a PageModel.
Singleton Class
public class GraphQLAPI
{
public static GraphQLAPI Instance {
get
{
if (_instance == null)
_instance = new GraphQLAPI();
return _instance;
}
}
private static GraphQLAPI _instance;
private GraphQLAPI()
{
_qlClient = new GraphQLHttpClient("XXX", new SystemTextJsonSerializer());
_qlClient.HttpClient.DefaultRequestHeaders.Add("Authorization", "XXX");
}
[...]
}
Is it even possible? If not, is there another way to pass the value to my client?

I just created 2 static fields in the GraphQLAPI.cs which will be set in the Startup.cs
GraphQLAPI.cs
public class GraphQLAPI
{
public static string GraphQLHostUrl { get; set; }
public static string GraphQLAuthorization { get; set; }
[...]
private GraphQLAPI()
{
_qlClient = new GraphQLHttpClient(GraphQLHostUrl, new SystemTextJsonSerializer());
_qlClient.HttpClient.DefaultRequestHeaders.Add("Authorization", GraphQLAuthorization);
}
[...]
}
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
GraphQLAPI.GraphQLHostUrl = configuration.GetValue<string>("GraphQlUrl");
GraphQLAPI.GraphQLAuthorization = configuration.GetValue<string>("ApiAuthorization");
}
[...]
}

Related

Singleton instance does not contain set properties

Update:
Vote to close this please, my mistake where I was assigning the Authorisation I wasn't assigning it to the instance.
I'm having an issue with the following code, basically I have two classes which are singletons within, they are declared at the top of my "MainWindow":
public partial class MainWindow : MetroWindow
{
public Auth AuthInfo = Auth.GetInstance();
public api myApi = api.GetInstance();
The line that sets it a bit further down within the MainWindow class, if I debug this after the assignment the Authorisation string is set.
AuthInfo = JsonConvert.DeserializeObject<Auth>(responseString);
The class declarations are as follows:
Auth
public class Auth
{
private static Auth instance = new Auth();
private Auth(){}
public static Auth GetInstance()
{
return instance;
}
public string Authorisation { get; set; }
}
api
public class api
{
private static api instance = new api();
Auth AuthInfo = Auth.GetInstance();
private api(){}
public static api GetInstance()
{
return instance;
}
// other code goes here
}
The problem is when I try and access the Authorisation property of the Auth instance from within the api class it's not set? It's almost like GetInstance returns the instance without any properties?
From within the MainWindow class the authorisation property is correct
Try this:
public class Auth
{
private static Auth instance = new Auth();
private Auth(){}
public static Auth GetInstance()
{
if (instance == null) \\ADDED
instance = new Auth();
return instance;
}
public string Authorisation { get; set; }
}
Instantiate in the static method itself:
public class Auth
{
private static Auth instance;
private Auth(){}
public static Auth GetInstance()
{
if (instance == null)
instance = new Auth();
return instance;
}
public string Authorisation { get; set; }
}

Singleton class for an object with parameters

I realized that I should have only one instance of an object called StdSchedulerFactory running at a time. So far I instantiated the object like this
StdSchedulerFactory sf = new StdSchedulerFactory(properties);
And properties is a NameValueCollection.
How can I write a Singleton class for this object so that the variable sf will always have one instance throughout the program?
Part of the Singleton pattern is typically a private constructor, so that other classes can not make new instances.
The workaround for parameters coming from outside the class is to add a "Init" or "Configure" function:
public static void Configure(NameValueCollection properties)
{
}
Of course, if you forget to call this function, you may get behavior you don't want; so you may want to set a "Configured" flag or something like that so your other functions can react appropriately if this function has not yet been called.
Here is a basic Singleton implementation. It is not thread-safe.
public sealed class StdSchedulerFactory
{
private static readonly StdSchedulerFactory instance;
private NameValueCollection _properties;
private StdSchedulerFactory(NameValueCollection properties)
{
_properties = properties;
}
public static StdSchedulerFactory GetInstance(NameValueCollection properties)
{
if (instance == null)
{
instance = new StdSchedulerFactory(properties);
}
else
{
return instance;
}
}
}
this is my two favorite way implementing simple singleton pattern. The second one is just easier when debugging :)
public sealed class SingletonOne
{
private static readonly Lazy<SingletonOne> instance = new Lazy<SingletonOne>(() => new SingletonOne());
private Lazy<Controller> controller = new Lazy<Controller>(() => new Controller(properties));
private static object properties = null;
public static SingletonOne Instance { get { return instance.Value; } }
public Controller GetController(object properties)
{
SingletonOne.properties = properties;
return this.controller.Value;
}
}
public sealed class SingletonTwo
{
private static readonly SingletonTwo instance = new SingletonTwo();
private Controller controller;
private static object properties = null;
public static SingletonTwo Instance
{
get
{
return SingletonTwo.instance;
}
}
public Controller GetController(object properties)
{
SingletonTwo.properties = properties;
if(this.controller == null)
{
this.controller = new Controller(SingletonTwo.properties);
}
return this.controller;
}
}
public class Controller
{
public Controller(object properties) { }
}

property injection using autofac 3.1.1

i am trying to inject through property in the following service, if I try constructor injection it works but I want to do property injection, what am I missing?
public class SodaService
{
public ISoda _s;
//public SodaService(ISoda s)
//{
// _s = s;
//}
public string GetSoda()
{
return _s.SodaName;
}
}
//Soda Class implementing ISoda
public class Soda : ISoda
{
public string SodaName
{
get { return "Default Soda"; }
}
}
public interface ISoda
{
string SodaName { get; }
}
//Main calling program
class Program
{
static void Main(string[] args)
{
var container = GetContainer();
SodaService s=container.Resolve<SodaService>();
Console.Write(s.GetSoda());
Console.Read();
}
private static IContainer GetContainer()
{
var builder = new ContainerBuilder();
builder.RegisterType<Soda>().As<ISoda>();
builder.RegisterType<SodaService>()
.PropertiesAutowired();
var container = builder.Build();
return container;
}
}
EDIT:
The above was solved and i have one more question....
How can i make something like this work, i do not want to use
s = container.Resolve< ISodaService >();
and instead the dependencies should be automatically injected when i run the program
class Program
{
public static ISodaService s { get; set; }
static void Main(string[] args)
{
SetUpContainer();
//s = container.Resolve<ISodaService>();
Console.Write(s.GetSoda());
Console.Read();
}
private static void SetUpContainer()
{
var builder = new ContainerBuilder();
builder.RegisterType<Soda>().As<ISoda>();
builder.RegisterType<SodaService>().As<ISodaService>().PropertiesAutowired();
builder.Build();
}
}
The problem you have is Main method is static. Instanciate a class of Program and use is as non static class
class Program
{
public ISodaService s { get; set; }
static void Main(string[] args)
{
var resolver=SetUpContainer();
var instance=resolver.Resolve<Program>();
instance.Execute(args);
}
public void Execute(string[] args)
{
Console.Write(s.GetSoda());
Console.Read();
}
private Autofac.IContainer void SetUpContainer()
{
var builder = new ContainerBuilder();
builder.RegisterType<Soda>().As<ISoda>();
builder.RegisterType<SodaService>().As<ISodaService>().PropertiesAutowired();
builder.RegisterType<Program>().PropertiesAutowired();
return builder.Build();
}
}

Getting Ninject to work

Clearly, I am missing something. I have an MVC application and have installed Ninject 3 and the MVC3 extensions (although I am running MVC4). I have a SiteSettings class that is referenced throughout the project, which looks like this:
public class SiteSettings
{
private static readonly Common.Logging.ILog Logger = Common.Logging.LogManager.GetCurrentClassLogger();
private static ObservableDictionary<string, string> settings;
private static bool Initialized = false;
private static DataPersister persister;
public static void Initialize()
{
if (Initialized) throw new InvalidOperationException("The SiteSettings object has already been initialized.");
persister = new DataPersister();
using (var u = persister.UnitOfWorkFactory.GetUnitOfWork())
{
var settingsList = u.SiteSettings.GetAll();
settings = new ObservableDictionary<string, string>(settingsList.ToDictionary(key => key.SiteSettingName, value => value.SiteSettingValue));
settings.OnChange += new kvpChangeEvent<string, string>(settings_OnChange);
}
Initialized = true;
}
static void settings_OnChange(object sender, odKVPChangeEventArgs<string, string> e)
{
using (var u = persister.UnitOfWorkFactory.GetUnitOfWork())
{
var setting = u.SiteSettings.GetByName(e.Key);
setting.SiteSettingValue = e.Value;
u.SiteSettings.Update(setting);
u.Save();
Logger.Info(i => i("Changed the '{0}' site setting from '{1}' to '{2}'.", e.Key, e.OldValue, e.Value));
}
}
private static int _ItemsPerPage;
public static int ItemsPerPage
{
get
{
return _ItemsPerPage;
}
set
{
_ItemsPerPage = value;
settings["itemsPerPage"] = value.ToString();
}
}
private static int _SessionLifeInMinutes;
public static int SessionLifeInMinutes
{
get
{
return _SessionLifeInMinutes;
}
set
{
_SessionLifeInMinutes = value;
settings["sessionLifeInMinutes"] = value.ToString();
}
}
private static string _DateFormat;
public static string DateFormat
{
get
{
return _DateFormat;
}
set
{
_DateFormat = value;
settings["defaultDateFormat"] = value;
}
}
}
I built a data persistence object like so:
public class DataPersister
{
public IUnitOfWorkFactory UnitOfWorkFactory { get; set; }
}
... and I have my NinjectWebCommon.cs looks like this:
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUnitOfWork>().To<NHUnitOfWork>();
kernel.Bind<IUnitOfWorkFactory>().To<NHUnitOfWorkFactory>();
}
}
It seems to me I've met all my requirements for dependency injection. My Global.asax.cs Application_Start() looks like this:
protected void Application_Start()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MonoRazorViewEngine());
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.DefaultNamespaces.Add("MyApplication.Application.Controllers");
Initialize.Security();
SiteSettings.Initialize();
}
...and yet, my SiteSettings class always has a null IUnitOfWorkFactory when I try to collect the data I need.
What am I doing wrong? Everything seems to be as all the examples suggest it should be, but I get no love.
UPDATE
Using Bassam Mehanni's advice, I rewrote my DataPersister class to look like this:
public class DataPersister
{
private IUnitOfWorkFactory UnitOfWorkFactory;
public DataPersister(IUnitOfWorkFactory unitOfWorkFactory)
{
UnitOfWorkFactory = unitOfWorkFactory;
}
public IUnitOfWork GetUnitOfWork()
{
return UnitOfWorkFactory.GetUnitOfWork();
}
}
...but of course now my SiteSettings class complains about my parameterless constructor. What should I do about that?
UPDATE 2
Ok, continuing on, I rewrote my DataPersister class like so:
public class DataPersister
{
private static readonly Common.Logging.ILog Logger = Common.Logging.LogManager.GetCurrentClassLogger();
private IUnitOfWorkFactory UnitOfWorkFactory { get; set; }
public IUnitOfWork GetUnitOfWork()
{
return UnitOfWorkFactory.GetUnitOfWork();
}
[Inject]
public DataPersister(IUnitOfWorkFactory factory)
{
Logger.Info("Injected constructor called");
UnitOfWorkFactory = factory;
}
public DataPersister()
{
Logger.Info("Parameterless constructor called");
}
}
then I rewrote my SiteSettings class like so:
public class SiteSettings
{
private static readonly Common.Logging.ILog Logger = Common.Logging.LogManager.GetCurrentClassLogger();
private ObservableDictionary<string, string> settings;
private DataPersister persister;
private SiteSettings()
{
persister = new DataPersister();
using (var u = persister.GetUnitOfWork())
{
var settingsList = u.SiteSettings.GetAll();
settings = new ObservableDictionary<string, string>(settingsList.ToDictionary(key => key.SiteSettingName, value => value.SiteSettingValue));
settings.OnChange += new kvpChangeEvent<string, string>(settings_OnChange);
}
}
private static SiteSettings instance;
public static SiteSettings Instance
{
get
{
if (instance == null)
{
instance = new SiteSettings();
}
return instance;
}
}
private void settings_OnChange(object sender, odKVPChangeEventArgs<string, string> e)
{
using (var u = persister.GetUnitOfWork())
{
var setting = u.SiteSettings.GetByName(e.Key);
setting.SiteSettingValue = e.Value;
u.SiteSettings.Update(setting);
u.Save();
Logger.Info(i => i("Changed the '{0}' site setting from '{1}' to '{2}'.", e.Key, e.OldValue, e.Value));
}
}
private int _ItemsPerPage;
public int ItemsPerPage
{
get
{
return _ItemsPerPage;
}
set
{
_ItemsPerPage = value;
settings["itemsPerPage"] = value.ToString();
}
}
private int _SessionLifeInMinutes;
public int SessionLifeInMinutes
{
get
{
return _SessionLifeInMinutes;
}
set
{
_SessionLifeInMinutes = value;
settings["sessionLifeInMinutes"] = value.ToString();
}
}
private string _DateFormat;
public string DateFormat
{
get
{
return _DateFormat;
}
set
{
_DateFormat = value;
settings["defaultDateFormat"] = value;
}
}
}
Shouldn't this work? because it doesn't. The DataPersister class always gets called with the parameterless constructor. My kernel binding looks like this:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUnitOfWork>().To<NHUnitOfWork>();
kernel.Bind<IUnitOfWorkFactory>().To<NHUnitOfWorkFactory>();
}
Is there something else I am missing? This is getting very frustrating.
Static classes that depencend on none static classes is something you shouldn't do when using an IoC container. Instead you should create a none static class with a singleton lifetime.
Make your SiteSettings class none static.
Inject all dependencies e.g. IUnitOfWorkFactory into SiteSettings using constructor injection
Create a binding in singleton scope for SiteSettings
Get an instance of SiteSettings wherever you need access unsing constructor injection.
Example:
public class SiteSettings {
public SiteSettings(IUnitOfWorkFactory uowFactory) { .... }
....
}
public class INeedToAccessSiteSettings
{
public INeedToAccessSiteSettings(SiteSettings siteSettings) { .... }
}
kenrel.Bind<SiteSettings>().ToSelf().InSingletonScope();
Typically ninject will inject your service in a constructor or something, it doesn't magically turn all your interfaces to object instances at run time
e.g.:
public class MyController : Controller
{
private IServiceThatINeed _serviceThatINeed;
public MyController(IServiceThatINeed serviceThatINeed)
{
_serviceThatINeed = _serviceThatINeed;
}
}
in this case since you registered your kernel instance, mvc knows how to resolve this dependence and will pass an instance of an object that implement IServiceThatINeed (assuming that you told ninject how to resolve this dependency.
Now there might be instance where you will need to get a service without it being injected in a constructor by the mvc framework, in these instances (like the one you have here), you will need to use ServiceLocator
e.g.:
var myService = ServiceLocator.Current.GetInstance<IServiceThatINeed>()
to use the ServiceLocator, you need to add a reference to Microsoft.Practices.ServiceLocation
Hope that helps!

Sourcing AppSettings from database & cache

At my office, it has been deemed that we are to put our AppSettings for the Web.Config in the database. As such, I created the following, but have some doubts about a couple aspects of the code.
So my question is:
The line containing "Cache cache = new Cache()" in the UTILITY class is probably wrong because it creates a NEW cache object.
Q: So, what should I be doing for that line?
...any help is appreciated.
The overall objective was to be able to make a call like this:
Utility.GetConfigurationValue(ConfigurationSection.AppSettings, "myVariable");
...and have it retrieve from the cache or the database auto-magically.
THE UTILITY CODE:
public static class Utility
{
#region "Configurations"
public static String GetConfigurationValue(ConfigurationSection section, String key)
{
Configurations config = new Configurations();
Cache cache = new Cache(); // <--- This is probably wrong!!!!
if (!cache.TryGetItemFromCache<Configurations>(out config))
{
config.List(SNCLavalin.US.Common.Enumerations.ConfigurationSection.AppSettings);
cache.AddToCache<Configurations>(config, DateTime.Now.AddMinutes(15));
}
var result = (from record in config
where record.Key == key
select record).FirstOrDefault();
return (result == null) ? null : result.Value;
}
#endregion
}
THE EXTENSION CODE:
public static class Extensions
{
#region "System.Web.Caching"
public static void Remove<T>(this Cache cache) where T : class
{
cache.Remove(typeof(T).Name);
}
public static void AddToCache<T>(this Cache cache, object item, DateTime absoluteExpiration) where T : class
{
T outItem = null;
if (cache.TryGetItemFromCache<T>(out outItem))
return;
cache.Insert(typeof(T).Name,
item,
null,
absoluteExpiration,
System.Web.Caching.Cache.NoSlidingExpiration,
System.Web.Caching.CacheItemPriority.Normal,
null);
}
public static bool TryGetItemFromCache<T>(this Cache cache, out T item) where T : class
{
item = cache.Get(typeof(T).Name) as T;
return item != null;
}
#endregion
}
THE LIST-CLASS CODE:
public class Configurations : List<Configuration>
{
#region CONSTRUCTORS
public Configurations() : base()
{
initialize();
}
public Configurations(int capacity) : base(capacity)
{
initialize();
}
public Configurations(IEnumerable<Configuration> collection) : base(collection)
{
initialize();
}
#endregion
#region PROPERTIES & FIELDS
private Crud _crud;
#endregion
#region EVENTS
#endregion
#region METHODS
private void initialize()
{
_crud = new Crud("CurrentDbConnection");
}
public Configurations List(ConfigurationSection section)
{
using (DbCommand dbCommand = _crud.Db.GetStoredProcCommand("spa_LIST_SecConfiguration"))
{
_crud.Db.AddInParameter(dbCommand, "#Section", DbType.String, section.ToString());
_crud.List(dbCommand, PopulateFrom);
}
return this;
}
public void PopulateFrom(DataTable table)
{
this.Clear();
foreach (DataRow row in table.Rows)
{
Configuration instance = new Configuration();
instance.PopulateFrom(row);
this.Add(instance);
}
}
#endregion
}
THE ITEM-CLASS CODE:
public class Configuration
{
#region CONSTRUCTORS
public Configuration()
{
initialize();
}
#endregion
#region PROPERTIES & FIELDS
private Crud _crud;
public string Section { get; set; }
public string Key { get; set; }
public string Value { get; set; }
#endregion
#region EVENTS
#endregion
#region METHODS
private void initialize()
{
_crud = new Crud("CurrentDbConnection");
Clear();
}
public void Clear()
{
this.Section = "";
this.Key = "";
this.Value = "";
}
public void PopulateFrom(DataRow row)
{
Clear();
this.Section = row["Section"].ToString();
this.Key = row["Key"].ToString();
this.Value = row["Value"].ToString();
}
#endregion
}
You have correctly identified the problem - the current code creates a new Cache instance on each call to GetConfigurationValue which defeats the purpose of caching. You need to make the Cache instance static rather than creating a new instance each time.
public static class Utility
{
private static Cache cache = new Cache(); // Static class variable
#region "Configurations"
public static String GetConfigurationValue(ConfigurationSection section, String key)
{
Configurations config = new Configurations();
// Cache cache = new Cache(); --- removed
...
}
}
ADDENDUM TO ANSWER:
I did (in fact) need to point the cache variable to something else. It wouldn't work until I did the following in the Utility class.
private static Cache cache = System.Web.HttpRuntime.Cache;

Categories