loading configuration settings from a database - c#

I'm currently writing a MVVMC application in C# (utilising Entity Framework).
What is the correct (best practice) way for loading and storing configuration values?
First of all, there is the question of how to store the configuration settings... would the best way to have the table designed like this: tblConfig(configid, configref, configval) or like this: tblConfig(configid,option1,option2,option3) - replacing option1 etc, with meaningful names (e.g. logoimage)
Next, there is how to retreive/store the settings in the app; My idea was to store the configuration in a table in the database, and then create a static class - something like this:
public static class ConfigClass
{
public static ConfigClass()
{
//load values from database
ContextClass SiteContext = new ContextClass();
logoImage = SiteContext.ConfigSettings.ToList().Find(c => c.configreference == "logoimage").configvalue;
admintoauthoriseaccounts = Convert.ToBoolean(SiteContext.ConfigSettings.ToList().Find(c => c.configreference == "logoimage").configvalue);
defaultaccountrole = Convert.ToInt32(SiteContext.ConfigSettings.ToList().Find(c => c.configreference == "logoimage").configvalue);
}
public static string logoImage = "";
public static bool admintoauthoriseaccounts = true;
public static Int32 defaultaccountrole = 1;
}
Class for the ConfigSetting DbSet Repository:
public class ConfigSetting
{
public string configreference { get; set; }
public string configvalue { get; set; }
}
Is this a good idea? Or should I forget the static class and just read settings directly out of the the DbSet repository?
Thanks.

Most common practice is to store configuration --including the string to connect to that database-- in app.config (or web.config) for the project. Any settings you store in the database would only add the value to, i guess, allow user modification.
If that's your goal:
Store user customization settings in db
Store application config in app.config/web.config
Otherwise:
Store both in app.config.
Serve to the rest of your layers via class, static class, singleton pattern, what have you.
Regardless of that choice:
Best if you do not use static class to hit the database over and over again for settings. This will cause performance degradation.
Branding like a logoimage doesn't sound like something that needs to change often, or per user, and wouldn't really be worth storing in a database.

Related

How to access CRUD operations of single db class instance without static methods

I'm new to NoSql and MongoDB. I'm using the MongoDB C# driver inside Visual Studio.
I've read in different places that it's preferable to have a single instance of your database class that maintains the connection(s) to keep everything thread safe and that it's generally a bad idea to use static classes for database CRUD operations.
At the start of my program I instantiate my database class which opens a connection. Within that class and also in derived classes I can perform CRUD operations. But now I'm in a different part of my solution (same namespace, different class) and I need to do read operations to check if a user exists. I also need to compose a new document that I then want to insert.
Now I'm in a situation where that's only possible by creating a new instance of the database class to access its CRUD methods. I want to avoid static CRUD methods (that could be accessed from other classes) because then the base class of my database connection also needs to be static. I cannot figure out how to approach this and what would be the recommended way.
From the MongoDB website:
The MongoClient instance actually represents a pool of connections to the database; you will only need one instance of class MongoClient even with multiple threads.
http://mongodb.github.io/mongo-csharp-driver/2.2/getting_started/quick_tour/
Does this mean I should create a new MongoClient everytime I need to acces the database in others parts of my program?
UPDATE
It seems I was a bit mistaken about the static properties and how they can be used. I now have it setup like this:
class Database
{
const string MongoConnection = "mongodb+srv://user:password#cluster.mongodb.net";
public static MongoClient Client { get; set; }
public static IMongoDatabase Directory { get; set; }
public static IMongoCollection<User> Collection { get; set; }
public Database()
{
Client = new MongoClient(MongoConnection);
Directory= Client.GetDatabase("studentDB");
Collection = Directory.GetCollection<User>("users");
}
public static void InsertNewUser(User user)
{
Collection.InsertOne(user);
}
public static bool EmailHasAccount(string email)
{
return Collection.Find(x => x.Email == email).FirstOrDefault() == null ? false : true;
}
public static User RetrieveUserAccount(string email)
{
return Collection.Find(x => x.Email == email).FirstOrDefault();
}
}
public class User
{
public Guid Id { get; private set; }
public string Name { get; set; }
public string Email { get; set; }
public User(string name, string email)
{
Id = Guid.NewGuid();
Name = name;
Email = email;
}
}
And in my main program I can use it like this:
var db = new Database();
var user = new User("myName", "email#address");
Database.InsertNewUser(user);
Console.WriteLine(Database.EmailHasAccount("email#address")); // returns true
Console.WriteLine(Database.RetrieveUserAccount("email#address").Name); // returns "myName"
That's exactly what I was looking for. What would be the best way to handle multiple collections? Would it be safe to change the Collection property or is it better to create separate properties? Is a Generic even possible?

How to create collection without database in .net core

How can I add items to my list SearchedVideos?
I would like to have these items on the list until the end of my application.
Now I have error like this:
NullReferenceException: Object reference not set to an instance of an object.
I create context with prop as Singleton like this:
public List<QueryViewModel> SearchedVideos { get; set; }
In startup
services.AddSingleton<YtContext>();
My model
public class ExecutedQuery
{
public Query Query { get; }
public string Title { get; set; }
public IReadOnlyList<Video> Videos { get; set; }
public ExecutedQuery(Query query, string title, IReadOnlyList<Video> videos)
{
Query = query;
Title = title;
Videos = videos;
}
}
My service
public async Task<ExecutedQuery> ExecuteQueryAsync(Query query)
{
// Search
if (query.Type == QueryType.Search)
{
var videos = await _youtubeClient.SearchVideosAsync(query.Value);
var title = $"Search: {query.Value}";
var executedQueries = new ExecutedQuery(query, title, videos);
var qw = new QueryViewModel
{
ExecutedQueries = executedQueries,
};
_ytcontext.SearchedVideos.Add(qw);
return executedQueries;
}
}
My QueryViewModel
public ExecutedQuery ExecutedQueries { get; set; }
My Controller
[HttpGet("Search/all")]
public async Task<IActionResult> ListAllQueriesAsync(string query)
{
var req = _queryService.ParseQuery(query);
var res = await _queryService.ExecuteQueryAsync(req);
return View(res);
}
If you are wanting to edit this list from one instance to another then you'll need to use some kind of datasource. If a database is not an option then a text file will have to do. Use a Json string and serialize/deserialize to your object. https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-serialize-and-deserialize-json-data. I've used this method to mockup an application but if you are going to be doing alot of writing to the file you may run into issues.
If you can hard code the list in the application then a Singleton will work. Read up here. https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2
Each request is its own thing, unaffected by anything that's happened before or since. As such, you pretty much start from a blank slate. The typical means for persisting state between one or more additional requests is the session. Sessions are essentially fake state, through a combination of server-side (some persistent store) and client-side components (cookies), something that appears like persistence of state can be achieved. However, particularly on the server-side, you still need some sort of store, which is generally a database of some sort, be it relational (SQL Server, etc.) or NoSQL (Redis, etc.). The default session store will be in-memory, which may suffice for your needs, but as memory is volatile, any sort of app restart will take anything stored there along with it.
Alternatively, there's statics and objects with singleton lifetimes. In either case, they're virtually the same as in-memory storage - they'll persist the life of the application and no more.
Statics are just members with a static keyword on them. It's probably the simplest and most straight-forward approach, but also the most fragile. It's virtually impossible to test statics, so you're basically creating black-holes in your code where anything could happen.
A better approach is to simply use an object with a singleton lifetime. These can be create via the AddSingleton<T> method on the service collection. For example, you could create a class like:
public class MySingleton
{
public ICollection<IReadOnlyList<Video>> SearchedVideo { get; set; }
}
And then register it as a singleton in ConfigureServices:
services.AddSingleton<MySingleton>();
Then, in your controllers, views, and such, you can inject MySingleton to access the SearchedVideos property. As a singleton, the data there will persist for the life of the application.
The chief difference between sessions, particularly in-memory sessions, and either statics or singletons is one of breadth. Sessions will always be tied to a particular client, whereas statics and singletons will be scoped to the application. That means that if you use statics or singletons, all clients will see the same data and will potentially manipulate the same data. If you need something that is client-specific, you must use sessions, instead.
#natsukiss i guess you are trying to call Add() method from null property. Even you create a list you should set an initial instance for SearchedVideo Property. Because if you dont create an instance, it means that property will not have address in memory. Because of that sometimes we are using string TestVal = "". That means we sets initial value on Common Language Runtime(CLR) to locate Address in Memory.
public List<QueryViewModel> SearchedVideos { get; set; } = new List<QueryViewModel>(); //<==
or if you are working with EntityFramework you should use
public ICollection<QueryViewModel> SearchedVideos { get; set; } = new HashSet<QueryViewModel>(); //<===

Save data in file used in multiple ViewModels

So I'm not sure if it is correct for me to ask this, but I've been self learning WPF and I can't figure out a method to save the data the user enters in my application.
Let's say a project requires the user to input a IList<int> of values. So I have a class storing that information. This information can be loaded from a json filed if the user has already input it and saved within the application.
public class Vault : BindableBase
{
public Vault(string savedFilePath = null)
{
if (string.IsNullOrEmpty(savedFilePath))
{
Measures = new List<int> { 1, 2, 3, 4 };
}
else
{
Measures = (List<int>)JsonConverter.DeserializeObject<List<int>>(savedFilePath);
}
}
public IList<int> Measures { get; set; }
}
Now, when I create the application view, I want to load all the ViewModels the user will use. In each ViewModel, an element of the Measures List must go.
public MainWindowViewModel()
{
vault = new Vault(savedFilePath);
Collection = new ObservableCollection<object>
{
new FirstViewViewModel(vault.Measures[0]),
new SecondViewViewModel(vault.Measures[1])
};
}
So that when I press Save, the Vault class can be serialized.
public void Save()
{
File.WriteAllText(fileLocation, JsonConvert.SerializeObject(vault));
}
As I want to modify the values in Vault with the user input, I need a direct reference to it, therefore in the ViewModels what I do is
public class FirstViewViewModel : BindableBase
{
private int _measure;
public FirstViewViewModel(int measure)
{
_measure = measure;
}
public int Measure
{
get => _measure;
set => SetProperty(ref _measure, value);
}
}
Nevertheless this seems an awful way to connect the user input with the data i want to save in a file.
This is a simplified case of what I want to achieve. However I am sure there are a better way that would allow me to change the values in Vault when Raising a property on the ViewModel. Ideally one that would make UnitTest easy (I haven't started with that yet).
If anyone could offer me a clue to find a better method to deal with this kind of situation, I would really appreciate it.
This will probably get flagged for being too broad in scope, but in general you should serialize the data to a database. This article is a great place to start:
https://learn.microsoft.com/en-us/ef/ef6/modeling/code-first/workflows/new-database
If your data structures are very lite then you might want to use something like SQLite, which stores the database in a local file and doesn't require installing any 3rd-party applications along with your application. Plenty of info here on how to get that working with Entity Framework:
Entity Framework 6 with SQLite 3 Code First - Won't create tables

Is Redis a viable solution for a local cache?

In my scenario, I have a Winforms client that connects to WebApi2. The data is stored in a SQL Server database.
To speed up performance, I am researching if storing data in local cache is a viable solution. Preferably, the local cache should be stored in files instead of kept in-memory as RAM might be an issue. The data is all POCO classes, some being much more complex than others, and most classes being related to each other.
I have made a shortlist of which frameworks might be viable:
MemoryCache
MemCached
CacheManager
StackExchange.Redis
Local Database
Using MemoryCache, I would need to implement my own solution, but it will fit my initial requirements.
However, one common problem that I am seeing is the updating of related classes. For example, I have a relationship between CustomerAddress and PostCode. If I change some properties in a postcode object, I can easily update its local cache. But how is it possible to update/invalidate any other classes that use this postcode, in this case CustomerAddress?
Does any of the frameworks above have methods that help in this kind of situation, or is it totally dependent on the developer to handle such cache invalidation?
The CachingFramework.Redis library provides a mechanism to relate tags to keys and hashes so you can then invalidate them in a single operation.
I'm assuming that you will:
Store the Customer Addresses in Redis with keys like "Address:{AddressId}".
Store the Post Codes in Redis with keys like "PostCode:{PostCodeId}".
And that your model is something like this:
public class CustomerAddress
{
public int CustomerAddressId { get; set; }
public int CustomerId { get; set; }
public int PostCodeId { get; set; }
}
public class PostCode
{
public int PostCodeId { get; set; }
public string Code { get; set; }
}
My suggestion is to:
Mark the Customer Addresses objects on Redis with tags like "Tag-PostCode:{PostCodeId}".
Use a cache-aside pattern to retrieve the Customer Addresses and Post Codes from cache/database.
Invalidate the cache objects by tag when a Post Code is changed.
Something like this should probably work:
public class DataAccess
{
private Context _cacheContext = new CachingFramework.Redis.Context("localhost:6379");
private string FormatPostCodeKey(int postCodeId)
{
return string.Format("PostCode:{0}", postCodeId);
}
private string FormatPostCodeTag(int postCodeId)
{
return string.Format("Tag-PostCode:{0}", postCodeId);
}
private string FormatAddressKey(int customerAddressId)
{
return string.Format("Address:{0}", customerAddressId);
}
public void InsertPostCode(PostCode postCode)
{
Sql.InsertPostCode(postCode);
}
public void UpdatePostCode(PostCode postCode)
{
Sql.UpdatePostCode(postCode);
//Invalidate cache: remove CustomerAddresses and PostCode related
_cacheContext.Cache.InvalidateKeysByTag(FormatPostCodeTag(postCode.PostCodeId));
}
public void DeletePostCode(int postCodeId)
{
Sql.DeletePostCode(postCodeId);
_cacheContext.Cache.InvalidateKeysByTag(FormatPostCodeTag(postCodeId));
}
public PostCode GetPostCode(int postCodeId)
{
// Get/Insert the postcode from/into Cache with key = PostCode{PostCodeId}.
// Mark the object with tag = Tag-PostCode:{PostCodeId}
return _cacheContext.Cache.FetchObject(
FormatPostCodeKey(postCodeId), // Redis Key to use
() => Sql.GetPostCode(postCodeId), // Delegate to get the value from database
new[] { FormatPostCodeTag(postCodeId) }); // Tags related
}
public void InsertCustomerAddress(CustomerAddress customerAddress)
{
Sql.InsertCustomerAddress(customerAddress);
}
public void UpdateCustomerAddress(CustomerAddress customerAddress)
{
var updated = Sql.UpdateCustomerAddress(customerAddress);
if (updated.PostCodeId != customerAddress.PostCodeId)
{
var addressKey = FormatAddressKey(customerAddress.CustomerAddressId);
_cacheContext.Cache.RenameTagForKey(addressKey, FormatPostCodeTag(customerAddress.PostCodeId), FormatPostCodeTag(updated.PostCodeId));
}
}
public void DeleteCustomerAddress(CustomerAddress customerAddress)
{
Sql.DeleteCustomerAddress(customerAddress.CustomerAddressId);
//Clean-up, remove the postcode tag from the CustomerAddress:
_cacheContext.Cache.RemoveTagsFromKey(FormatAddressKey(customerAddress.CustomerAddressId), new [] { FormatPostCodeTag(customerAddress.PostCodeId) });
}
public CustomerAddress GetCustomerAddress(int customerAddressId)
{
// Get/Insert the address from/into Cache with key = Address:{CustomerAddressId}.
// Mark the object with tag = Tag-PostCode:{PostCodeId}
return _cacheContext.Cache.FetchObject(
FormatAddressKey(customerAddressId),
() => Sql.GetCustomerAddress(customerAddressId),
a => new[] { FormatPostCodeTag(a.PostCodeId) });
}
}
To speed up performance, I am researching if storing data in local
cache is a viable solution. Preferably, the local cache should be
stored in files instead of kept in-memory as RAM might be an issue
The whole issue is to avoid storing it in files, to avoid DISK operations which are slow, thus Redis is RAM based memory.
Does any of the frameworks above have methods that help in this kind
of situation, or is it totally dependent on the developer to handle
such cache invalidation?
You can save the entire object as JSON instead of applying logic and disassembles the objects, which will be also slow and error prone when applying changes.

Property type of two classes

I'm writing session manager class in .NET MVC 4 and I got stuck at the point of creating SqlConfiguration.
Here is one of the properties from the class:
public static MsSqlConfiguration SqlConfig { get; set; }
All working perfectly excluding the fact that I can manage sessions only from MS SQLServer.
I want to do something like this:
public static MsSqlConfiguration,SQLiteConfiguration SqlConfig { get; set; }
And I know it isn't possible so I don't know what to do.
Thanks.
You can create a class with these 2 properties and Use them. I know its very basic
class MyConfig
{
public static MsSqlConfiguration SqlConfig { get; set; }
public static SQLiteConfiguration SQLiteConfig { get; set; }
}
Use them like
public static MyConfig SqlConfig { get; set; }
What about a dictionary?
public static IReadOnlyDictionary<string, IPersistenceConfigurer> DbConfigurations =
new ReadOnlyDictionary<string, IPersistenceConfigurer>(
new Dictionary<string, IPersistenceConfigurer>
{
{ "azure", MsSqlConfiguration.MsSql2008
.ConnectionString("ConnectionString")
.Dialect<MsSqlAzure2008Dialect>()
.Driver<SqlAzureClientDriver>() },
{ "mssql", MsSqlConfiguration.MsSql2008
.ConnectionString("ConnectionString")
.Dialect<MsSql2008Dialect>() },
{ "sqlite", SQLiteConfiguration.Standard
.InMemory() },
// etc..
});
IPersistenceConfigurer is an interface that any database configuration must implement.
As it's a dictionary, you can always check if a database configuration is present by calling DbConfigurations.ContainsKey("mssql").
Another option is using a generic list of IPersistenceConfigurer (aka List<IPersistenceConfigurer>) and get a configuration using LINQ OfType<T> extension method as follows:
dbConfigs.OfType<MsSqlConfiguration >().Single()
...or
dbConfigs.Single(config => config is MsSqlConfiguration)
Another option, if you're using Dependency Injection and an IoC container such as Castle Windsor is to register a factory with the container that can provide an instance of IPersistenceConfigurer to any components that require it. This way you can register different components for the IPersistenceConfigurer service depending on which environment you are running in (as I assume that you only need one particular IPersistenceConfigurer for the application at any one time).

Categories