Net6 Console app, custom ConfigurationProvider question - c#

I have a .Net6 Console application where I need to retrieve an array of objects from AppSettings.json. Currently I am using an 'options' class to retrieve the array.
class ConfigOpts { class subOpts { /* property accessors */ }, public List<subOpts> SubOpts {get;set;}}
and
var builder = new ConfigurationBuilder().SetBasePath(...).AddJsonFile(..);
IConfiguration config = build.build();
ConfigOpts opts = new ConfigOpts();
config.GetSection("ConfigOpts").Bind(opts);
Gives me an opts objects containing a list of subOpts.
One of the sub opt fields needs to be decrypted and encrypted at load/save time. So I would like to use a CustomConfigProvider and do the decrypt in the Load() method, and encrypt in a CreateSave() method.
I have amended my code to add a new class ConfigOptsProvider:ConfigurationProvider,IConfigurationSource and created an extension method AddConfigOptsProvider which is called on the binder above.
This works and I can hit the load() function in the config provider.
My two questions are:-
In the Load Method, how do I read the AppSettings.json file (I've looked for documentation but found examples for reading databases and other files but none for AppSettings.json).
Also, how do I call the CreateSave() function later?
Regards.
Update
I noticed as I have the ConfigOpts class that allows me to access the settings in a typed manner, it might be useful to try and use it.
In the load I have tried adding the following to the Load() method.
((IConfiguration)this).GetSection("ConfigOpts").Bind(_configOptions);
This code is what I originally used (in the first example above). Unfortunately one cant cast to IConfiguration.
It would be great if this is all I need to do.

My solution was to use the System.Text.Json.Nodes namespace to read the appsettings files as JSON and them process.
I ended up with this routine in my Load() method which populated an internal custom data class with the required data, I can then access using a Get method. Because of the number of fields in the data Class, it meant I cannot use the provided Data property to return the result.
var fp = _fileProvider.GetFileInfo("appsettings.json")
using (Stream s = fp.CreateReadStream())
{
var co = JsonDocument.Parse(s)?.Deserialize<Dictionary<String,Object>>?.Where(str => str.Key == "ConfigOpt").FirstOrDefault();
var subObts = JSonNode.Parse(co.GetValueOrDefault().Value.ToString())["SUbOpts"];
foreach(JsonNOde opt in subOpts.AsArray())
{
var optName = opt["name"]?.AsValue;
}
}
I have removed most of the null checks and the filesystem watcher and also there isn't a check for different environments (appsettings files). The structure is ConfigOpt:SubOpts:opt:property where SubOpts is an array of opts.

Related

Using a referenced C# object in a seperate class/form

I've got a Windows Form program that creates a Config object which contains various configuration variables used by my program.
Within the main form, it contains a button to open a new configuration form, where it passes the Config object as a reference -
FormConfig button = new FormConfig(ref config);
button.ShowDialog();
Now in the FormConfig class, I can access the Config object within the main constructor
public FormConfig(ref Config config)
{
InitializeComponent();
// can access config.xyz OK here
}
However within the new form, I've got a button that calls another function that needs to access the reference Config object, however I'm struggling to find a clean way to do so.
I can create another Config object as part of the FormConfig class, and then copy the referenced Config to it in the main constructor, however then the original config object doesn't get updated.
How can I achieve this?
PS apologies in advance if this is already answered, but my searches have so far failed to find a solution, possibly because I'm not sure what the correct search terms should be.
And the solution thanks to #cmos, is to declare the Config class as static, which negates the need to use any referencing or passing objects between classes/functions -
public static class Config
{
public static bool SettingA = true;
}
Which means I can access and modify the Config object from anywhere within the same namespace with the following code, without needing to have a class instance -
Config.SettingA
Thanks to all those who helped point me in the right direction.

C# .Net 3.5 : Extracting and binding Metadata to a file

Introduction
I am trying to make a compression application. The current obstacle I am facing is that whenever I try to compress my file I take a byte array from the file and apply compression algorithm on the byte array itself because of which the metadata of file is lost.
Question
Is there any method by which I can extract the metadata of a file on compression and later on extraction attach the metadata to the extracted file?
Visual Studio : VS2008
Framework : .Net 3.5
Solutions I found:
I have seen in many articles that they say we can use Windows Property System but even after reading the article I have no clue as to how can I implement it.
This website has explained with the code but they didn't give any download link for the DLL.
From this Stackoverflow answer I got this code:-
//creates new class of oledocumentproperties
var doc = new OleDocumentPropertiesClass();
//open your selected file
doc.Open(#"C:\Users\ABC\Desktop\Test\1.jpg", false, dsoFileOpenOptions.dsoOptionDefault);
//you can set properties with summaryproperties.nameOfProperty = value; for example
doc.SummaryProperties.Company = "lol"; //Line 8 : Shows error
doc.SummaryProperties.Author = "me";
//after making changes, you need to use this line to save them
doc.Save();
I get the following error on Line 8
The name is not valid. (Exception from HRESULT: 0x800300FC (STG_E_INVALIDNAME))
Are you sure that the Company property exists in your file metadata?
Try using a known existing property in the metadata of the file you're trying to access, as the ones that are used in the example may just not exist.
As for saving the properties, you can access some basic global ones like CreationTime and LastAccessTime from the System.IO.FileInfo object.
This article seems to describe a method through which you can get more specific properties from files, such as the Camera and CameraManufacturer properties (that isn't identical to the one from the StackOverflow question) like so:
using System;
using Microsoft.WindowsAPICodePack.Shell.PropertySystem;
using Microsoft.WindowsAPICodePack.Shell;
using System.Diagnostics;
class Program {
void getProperty() {
var cameraModel = GetValue(picture.Properties.
GetProperty(SystemProperties.System.Photo.CameraModel));
}
}
with GetValue being:
private static string GetValue(IShellProperty value)
{
if (value == null || value.ValueAsObject == null)
{
return String.Empty;
}
return value.ValueAsObject.ToString();
}

c# Local Application edit app without recompiling/reinstallation [duplicate]

I would like to store an API key in a configuration file without checking it into source control, and read the data in my UWP app.
A common solution is to store the key in .config file (such as app.config or web.config) and access it like so:
var apiKey = ConfigurationManager.AppSettings.Get("apiKey");
I'm working on a Universal Windows (UWP) app and can't access the System.Configuration namespace that holds ConfigurationManager.
How can I access AppSettings in UWP app?
Alternatively, what's the best way to access configuration data in an UWP app?
In my specific use case I needed to use an external file that is not tracked by source control. There are two ways to access data from resource or configuration files.
One is to open and parse a configuration file. Given a file sample.txt with Build Action Content (Copy to Output Directory doesn't matter), we can read it with
var uri = new System.Uri("ms-appx:///sample.txt");
var sampleFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri);
or
var packageFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
var sampleFile = await packageFolder.GetFileAsync("sample.txt");
followed by
var contents = await Windows.Storage.FileIO.ReadTextAsync(sampleFile);
Alternatively, we can use Resources. Add a new Resource item to the project, called resourcesFile.resw. To access data, use:
var resources = new Windows.ApplicationModel.Resources.ResourceLoader("resourcesFile");
var token = resources.GetString("secret");
I wrote more verbose answer in a blog post Custom resource files in UWP
It's an old question, but here my solution :
Create a partial class Config.cs (for example) with all the properties you'r needed
Add a partial method void Init()
Call Init in the constructor
Create an other file Config.partial.cs with the void Init() method filling all your properties
-> Use #if DEBUG / #else / #endif to switch from Debug/Release
-> Use exclude Config.partial.cs from Github to not import it in the repository
Now it compile and it's not in the repository
Alternatively you can set in Config.cs default (not secret) datas.
Config.cs :
public partial class Config
{
public Config()
{
Init();
}
partial void Init();
public string ApiKey{ get; private set; }= "DefaultValueAPIKEY";
}
Config.partial.cs
public partial class Config
{
partial void Init()
{
#if DEBUG
this.ApiKey = "DebugAPIKEY";
#else
this.ApiKey = "ReleaseAPIKEY";
#endif
}
}
I'm thinking that what you call "ApiKey" is the static key that an API gives you to generate an access token. If this is the case, maybe the best way to achieve this is to create a static class out of the source control with that value inside of it, something like this:
public static class MyCredentials
{
public static string MyApiKey = "apiKey";
}
Then you access that value easily from your code:
var myApiKey = MyCredentials.MyApiKey;
If you want to store values in a plain-text file instead you will have to write/read it manually using StorageFile and FileIO classes.
Instead, if "ApiKey" means the dynamic access token, then the best solution is use ApplicationDataContainer as stratever says.
You don't need to create a configuration file. UWP has a built-in solution to store local settings/configurations. Please check this tutorial:
https://msdn.microsoft.com/en-us/library/windows/apps/mt299098.aspx
Using ApplicationDataContainer, you will be able to get a value by key:
Object value = localSettings.Values["exampleSetting"];

Including a file when I publish my Azure function in Visual Studio

I know this seems like a simple thing but I can't find any help online.
I want to include a file (.html) along with my Azure function when I publish it using Visual Studio. Then I want to be able to access this file in my Azure function.
Why? It seems like only the .dll gets sent to the server when I publish.
This file will be an .html file that will be an email template. I want to read it in my function and then send emails out.
Any help is much appreciated.
I see I can use [send grid in Azure functions][1], but it looks like I can only send out one email and not multiple emails, which is what I want.
First, you need to add the html file to your project, and in the properties, set Copy to Output Directory to "Copy if newer".
Then in your function code, take in an additional ExecutionContext context parameter (note that this is Microsoft.Azure.WebJobs.ExecutionContext and not System.Threading.ExecutionContext). And when you need to access your html file, you can then write:
string htmlFilePath = Path.Combine(context.FunctionAppDirectory, "test.html");
That's assuming you added the file at the root of your VS project. If you instead added it in some Data folder (better practice), you'd write:
string htmlFilePath = Path.Combine(context.FunctionAppDirectory, "Data", "test.html");
See here for full working sample.
I have the same scenario as you have. However, I cannot access ExecutionContext because it is only available in requests. My scenario needs to get the template included in AzFunc project but not in the context of AzFunc's functions. I got it null when I go with the interface - implementation class approach.
Thanks to this guy, I use IOptions<ExecutionContextOptions> in my class to get the root directory of the Azure Func.
My Azure Func project (NET 6, Azure Function v4)
using Microsoft.Extensions.Options;
using Microsoft.Azure.WebJobs.Host.Bindings;
namespace AzureFuncApi
{
public class TemplateHelper : ITemplateHelper
{
private readonly IOptions<ExecutionContextOptions> _executionContext;
public TemplateHelper (IOptions<ExecutionContextOptions> executionContext)
{
_executionContext = executionContext;
}
public string GetTemplate()
{
var context = _executionContext.Value;
var rootDir = context.AppDirectory; // <-- rootDir of AzFunc
var template = Path.Combine(rootDir, "test.html"); // <-- browse for your template. Here's an example if you place test.html right in the root of your project
// return your template here, raw, or after you do whatever you want with it...
}
}
}
My different project defines the interface and uses it there, independently of the real implementation
namespace DifferentProject
{
public interface ITemplateHelper
{
string GetTemplate(); // Use this to get the template
}
}

ConfigurationManager and AppSettings in universal (UWP) app

I would like to store an API key in a configuration file without checking it into source control, and read the data in my UWP app.
A common solution is to store the key in .config file (such as app.config or web.config) and access it like so:
var apiKey = ConfigurationManager.AppSettings.Get("apiKey");
I'm working on a Universal Windows (UWP) app and can't access the System.Configuration namespace that holds ConfigurationManager.
How can I access AppSettings in UWP app?
Alternatively, what's the best way to access configuration data in an UWP app?
In my specific use case I needed to use an external file that is not tracked by source control. There are two ways to access data from resource or configuration files.
One is to open and parse a configuration file. Given a file sample.txt with Build Action Content (Copy to Output Directory doesn't matter), we can read it with
var uri = new System.Uri("ms-appx:///sample.txt");
var sampleFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri);
or
var packageFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
var sampleFile = await packageFolder.GetFileAsync("sample.txt");
followed by
var contents = await Windows.Storage.FileIO.ReadTextAsync(sampleFile);
Alternatively, we can use Resources. Add a new Resource item to the project, called resourcesFile.resw. To access data, use:
var resources = new Windows.ApplicationModel.Resources.ResourceLoader("resourcesFile");
var token = resources.GetString("secret");
I wrote more verbose answer in a blog post Custom resource files in UWP
It's an old question, but here my solution :
Create a partial class Config.cs (for example) with all the properties you'r needed
Add a partial method void Init()
Call Init in the constructor
Create an other file Config.partial.cs with the void Init() method filling all your properties
-> Use #if DEBUG / #else / #endif to switch from Debug/Release
-> Use exclude Config.partial.cs from Github to not import it in the repository
Now it compile and it's not in the repository
Alternatively you can set in Config.cs default (not secret) datas.
Config.cs :
public partial class Config
{
public Config()
{
Init();
}
partial void Init();
public string ApiKey{ get; private set; }= "DefaultValueAPIKEY";
}
Config.partial.cs
public partial class Config
{
partial void Init()
{
#if DEBUG
this.ApiKey = "DebugAPIKEY";
#else
this.ApiKey = "ReleaseAPIKEY";
#endif
}
}
I'm thinking that what you call "ApiKey" is the static key that an API gives you to generate an access token. If this is the case, maybe the best way to achieve this is to create a static class out of the source control with that value inside of it, something like this:
public static class MyCredentials
{
public static string MyApiKey = "apiKey";
}
Then you access that value easily from your code:
var myApiKey = MyCredentials.MyApiKey;
If you want to store values in a plain-text file instead you will have to write/read it manually using StorageFile and FileIO classes.
Instead, if "ApiKey" means the dynamic access token, then the best solution is use ApplicationDataContainer as stratever says.
You don't need to create a configuration file. UWP has a built-in solution to store local settings/configurations. Please check this tutorial:
https://msdn.microsoft.com/en-us/library/windows/apps/mt299098.aspx
Using ApplicationDataContainer, you will be able to get a value by key:
Object value = localSettings.Values["exampleSetting"];

Categories

Resources