ConfigurationManager and AppSettings in universal (UWP) app - c#

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"];

Related

Net6 Console app, custom ConfigurationProvider question

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.

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
}
}

Winform app: Compiled App.Config-like file?

I would like to know if there is some kind of built-in compiled "App.Config" file?
The goal is to be able to have one of our library which can have some of its default values overriden when being used in some client application.
Thoses DLL are loaded dynamically, so I cannot just give a parameter in the constructor.
I don't want to use the App.config file because the user can edit those values(otherwise it would have been just fine).
There are several different ways to solve this.
If you like the idea of config-files, but do not want to have it accessible by end users in the compiled application, perhaps you can create your own settings-file in a format that suits your needs, and include it as an embedded resource?
An upside of this would be that you can access it as a regular XML or config file or whatever in Visual Studio, while it will be hidden from the end user. Personally I think I would prefer this to using special code / classes to store config-data.
To include a file as an embedded resource, include it into one of your Visual Studio projects, right click the included file and select Properties. Now under Build Action, select Embedded Resource. When you build your project now, the file will be included internally in the produced .dll-file.
I'm sure you'll be able to find lot's of info about how to access an embedded resource from code. As an example, there are some useful examples in this SO question. Note especially this answer, which also mentions an alternative way to include a resource.
Expanding on my comment... you could just make an interface for a settings class with hardcoded values, and then make different implementations of that interface. To actually change which one to use, all you'd need to do is comment/uncomment the line that instantiates an object into your settings variable before you build the dll:
public class MainDllProject
{
ISettings m_Settings;
public MainDllProject()
{
// Change this before compiling
this.m_Settings = new DebugSettings();
//this.m_Settings = new DeploySettings();
// use settings from the settings class
String setting1 = this.m_Settings.Setting1
Int32 setting2 = this.m_Settings.Setting2
//...
}
}
public interface ISettings
{
String Setting1 { get; }
Int32 Setting2 { get; }
}
public class DebugSettings: ISettings
{
public String Setting1
{ get { return "data_debug";} }
public Int32 Setting2
{ get { return 2;} }
}
public class DeploySettings: ISettings
{
public String Setting1
{ get { return "data_deploy";} }
public Int32 Setting2
{ get { return 1;} }
}
On finding "a built-in way of solving this", as you said, maybe this will be useful for you...
You can actually use the Visual Studio build configuration manager to build with different settings. Using the #If directives, you can automatically make it select which lines of code to use based on the configuration. A simple example based on the default debug configuration, which adds the "DEBUG=True" variable automatically:
public MainDllProject()
{
#If DEBUG Then
this.m_Settings = new DebugSettings();
#ElseIf
this.m_Settings = new DeploySettings();
#End if
}
You can actually make your own custom-named variables to check on just like that DEBUG one: after making a configuration, open the Project properties window, go to the Compile tab, select that specific configuration in the dropdown, and then at the bottom select "Advanced Compile Options". In there is a line "Custom constants" in which you can add such variables. For simple if-statements, you can just make a boolean like "CLIENTDEPLOY=True", and then you can use #If CLIENTDEPLOY Then in your code.

App.config multi-project access strategies

My current solution has 3 project with 2 app.config (one for common settings and another for service settings). As of now I'm simply creating static classes to act as a mediator to access values. I do this so I don't have to write ConfigurationManager.AppSettings["SomeKey"] everywhere. This works fine until you want to access an app.config file from a different project.
Here is what I'm currently doing (all properties omitted for brevity).
public class ServiceConfiguration
{
public static readonly string SyncEvery = ConfigurationManager.AppSettings["SyncEveryMinutes"];
}
How can I access an app.config file located in another project? I thought perhaps setting VS to copy the file to the output directory would do the trick however my configuration object is still null.
I can't imaging many good reasons to read another app's configuration in the first place, it just opens a can of worms that isn't worth dealing with.
Expose a class that exposes the project's configured values as properties, and access them from a consuming class.
public class FirstProjectClass
{
public static int SyncEveryMinutes
{
get { return (int)ConfigurationManager.AppSetting["SyncEveryMinutes"] };
}
}
public class SecondProjectClass
{
public void ShowConfigedValue()
{
Console.Writeline("Syncing every {0} minutes", FirstProjectClass.SyncEveryMinutes);
}
}
if you've got complex configuration requirements you can also look into custom configuration sections
ConfigurationManager.OpenExeConfiguration can be helpfull:
http://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.openexeconfiguration.aspx
Also: what Jason said - it is usually a bad idea.

Categories

Resources