I wonder if there is a best practice for seting up a configuration file in a F# solution.
Below is a sample of my configuration file, which is used by different projects in my F# solution.
myConfig.xml :
<?xml version="1.0" encoding="utf-8" ?>
<Config>
<Segment>
<SegmentTypes>
<Did>did</Did>
<PostCode>postcode</PostCode>
<Ip>/ip</Ip>
</SegmentTypes>
</Segment>
<SThreeConfig>
<AccessKey>aaa</AccessKey>
<SecretKey>bb</SecretKey>
</SThreeConfig>
</Config>
I could put the contain of the above in the built in App.config. As App.config does not allow nested
tags, it will become messy as my configuration grows.
So far the best solution we have found is the following.
Create a top level project configuration, and in that project,
create a source file to read myConfig.xml using xml type provider.
Then wrap the values in myConfig.xml in static properties of
a class AppConfigObj. The other projects in the solution will access configuration properties
via appConfObj.
module Configuration=
open FSharp.Data
open System
// Other projects acccess the configuration properties using AppConfigObj.
type AppConfigObj() =
static let [<Literal>] configXmlFile = "myConfig.xml"
static let config = XmlProvider<configXmlFile>.Load(configXmlFile.ToString())
static member didPath = config.Segment.SegmentTypes.Did
static member postcodePath = config.Segment.SegmentTypes.PostCode
static member ipPath = config.Segment.SegmentTypes.Ip
static member s3AccessKey = config.SThreeConfig.AccessKey
static member s3SecreteKey=config.SThreeConfig.SecretKey
Although the default configuration mechanism is enough, there exists a very practical alternative which is using a config tailored type provider: FSharp.Configuration
This way you work with typed classes for config and setting files.
Related
I have a class called Constants.cs that contains app settings. I want to add an App.config file and put the settings from Constants.cs to App.config file in order to be able to run my application in different environments with same settings.
If my constants.cs class looks like this:
public class Constants
{
public static string LoginSubmitText => "Submit";
public static string LoginBackBtnText => "Back";
public static string SettingsPageTitleSize => "25";
}
Should then the App.config file look like this?
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key ="LoginSubmitText" value="Submit"/>
<add key ="LoginBackBtnText " value="Back"/>
<add key ="SettingsPageTitleSize" value="25"/>
</appSettings>
</configuration>
And in that case, must I put this App.config file in all three environments, .Android, .IOS and UWP?
Thanks in advance!
You don't have to have App.config in all three platfroms. You can add this class to project with shared code.
I just finished working on similar issue. This is described here in this article. They don't use App.config file and if you insist on having App.config you can write your own implementation of parsing App.config to AppSettings object. I am talking about the method LoadAppSettings. The last part of this method converts json file appsettings.debug.json to AppSettings obejct.
In my case I needed to inject different connection strings regarding to build configuration in my azure pipelines. I use the powershell script to edit appsettings.[build configuration].json file and that solves my issue.
I am building an app that mostly provide REST services, nothing fancy. since my data consumed by the app can have multiple languages I thought about using the bundle files.
I created 3 files, one with the default file name and another two with specific languages. The files created using intellij IDE I am using.
I followed this guide https://www.baeldung.com/java-resourcebundle however on each run I am getting:
MissingResourceException: Can't find bundle for base name tp_app_strings, locale en_US
I tried numerous articles but none of them seems to resolve the issue.
One fun fact is that if I am using the #Value("classpath:tp_app_strings.properties") on a 'Resource' field I am able to get a reference to that file, so it spring is able to find it.
Additional thing that I tried was to create a WEB-INF directory and place the files there (read it in some article) but still no positive affect
The project structure is quite straight forward:
Spring boot version 2.2 running tomcat.
Any suggeestions would be highly appriciated
You can load the .properties file to the application context using #PropertySource annotation instead using #Value to load the .properties file to a org.springframework.core.io.Resource instance.
The usage;
#Configuration
#PropertySource("classpath:tp_app_strings.properties")
public class DefaultProperties {
#Value("${property1.name}") // Access properties in the above file here using SpringEL.
private String prop1;
#Value("${property2.name}")
private String prop2;
}
You wouldn't need java.util.ResourceBundle access properties this way. Use different or same class to load other .properties files as well.
Update 1:
In order to have the functionality of java.util.ResourceBundle, you can't just use org.springframework.core.io.Resource class. This class or non of it sub-classes don't provide functions to access properties by its name java.util.ResourceBundle whatsoever.
However, if you want a functionality like java.util.ResourceBundle, you could implement something custom like this using org.springframework.core.io.Resource;
#Configuration
public class PropertyConfig {
#Value("classpath:tp_app_strings.properties")
private Resource defaultProperties;
#Bean("default-lang")
public java.util.Properties getDefaultProperties() throws IOException {
Properties props = new Properties();
props.load(defaultProperties.getInputStream());
return props;
}
}
Make sure to follow correct naming convention when define the property file as java.util.Properties#load(InputStream) expect that.
Now you can #Autowire and use this java.util.Properties bean wherever you want just like with java.util.ResourceBundle using java.util.Properties#getProperty(String) or its overloaded counterpart.
I think it's problem of you properties file naming convention. use underline "_" for specifying locale of file like
filename_[languageCode]_[regionCode]
[languageCode] and [regionCode] are two letters standard code that [regionCode] section is optional
about code abbrivation standard take a look on this question
in your case change file name to tp_app_strings_en_US.properties
I'm working on CQ5 based app, which is a whole new area for me as I was mainly working on Spring based web-apps before.
The app is maven project based on Blue-prints archetype(http://www.cqblueprints.com/xwiki/bin/view/Blue+Prints/The+CQ+Project+Maven+Archetype).
Now I have a question, what is a standard approach to add some properties, that would normally go to config.properties (or alike) file in standard web-app. Properties that contain things like hostNames, accountNumbers and alike.
Cheers.
I'm not familiar with blueprints, but as I understand that's just a way to generate your CQ project structure, so I assume it doesn't have any real impact on how you manage configuration parameters.
CQ5 is based on Apache Sling, which uses the OSGi ConfigAdmin service for configurable parameters, and provides a few tools to make this easier.
You can see an example of that in the PathBasedDecorator Sling component, which uses the #Component annotation to declare itself as an OSGi component:
#Component(metatype=true, ...)
and later uses an #Property annotation to declare a multi-value configurable parameter, with default values:
#Property(value={"/content:2", "/sling-test-pbrt:2"}, unbounded=PropertyUnbounded.ARRAY)
private static final String PROP_PATH_MAPPING = "path.mapping";
That value is then read in the component's activate() method:
final Dictionary<?, ?> properties = componentContext.getProperties();
final String[] mappingList = (String[]) properties.get(PROP_PATH_MAPPING);
and the OSGi bundle that contains that component provides a metatype.properties file to define the name and label of the configurable parameter.
That's it - with this, Sling and the OSGi framework generate a basic config UI for the component, that you can access from /system/console/config, and manage your component's activation and reactivation automatically if configuration parameters change.
Those configurations can also come from the JCR repository, thanks to the Sling installer which picks them up there, you can find a number of those in folders named "config" under /libs and /apps in your CQ5 repository.
Another option is to use JCR content directly, depending on how your configurable parameters are used. You could tell your component that its config is under /apps/foo/myparameters in the repository (and make just that value configurable), and add JCR properties and child nodes under that node as needed, that your component can read. The disadvantage is that your #Component won't be restarted automatically when parameters change, as happens when using OSGi configurations directly.
Long explanation...hope this helps ;-)
Thanks a lot to Bertrand, your answer really pointed me in the right direction.
What I did was I created .ConfigService.xml for each of my ran modes, which looks like that:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OsgiConfig"
myconfig.config="{String}My Value"/>
Then in my ConfigService looked like that:
#Component(immediate = true, metatype = true)
#Service(ConfigService.class)
public class ConfigService {
private Dictionary<String, String> properties;
#SuppressWarnings("unchecked")
protected void activate(ComponentContext context) {
properties = context.getProperties();
}
protected void deactivate(ComponentContext context) {
properties = null;
}
public String getProperty(String key) {
return properties.get(key);
}
}
Than I just use ConfigService if I need to get a config property accessing it using #Reference.
I hope that can help someone!
ConfigService example may not be the best approach since the ComponentContext should only be depended upon during component activation and deactivation.
hi i am having a different projects in my solution in the initial project (default project) i am accessing the global reference to App.xaml.cs in this way :-
App objref = (App)Application.Current;
But now i have added new project to my solution and trying to access the app.xaml.cs in the same way as defined earlier but i am not able to access app.xaml.cs ?
1)can i know the reason
2)What should i do if i want to use it in both the projects ?
Please let me know
Thanks in advance.
You can access it, but the new project will not be familiar with the derived App class that is in your project. To explain further we need to take inheritance into consideration.
There's a generic definition for the Application class that exposes a number of predefined methods. Your App.xaml.cs is a new class definition that is derived from the Application class. It has the methods it inherited plus what ever methods and properties that you've added. To make use of these any code that is seeking to use your extra properties or methods must have access to the class definition. Your classes in the other projects that you've added do not have access to this definition.
You'll need to make a class or interface definition that both projects have access to. There are several ways of organizing this. I'll present one.
Create your main project in the solution. This contains your
App.xaml.cs.
Create your class library project that contains the
other code.
Create a third project called Common that only contains
an Interface definition.
On the Interface definition define all of the methods/properties
that you want both your class library and main project to have
access too.
Have App.Xaml.cs implement this interface.
In the Class Library access var appReference =
(IMyInterfaceName)Applcation.Current. You'll have access to the
methods that were defined in the interface
I have a web application that I need to manually obtain a Freemarker template - the template is obtained via a class in a library project, but the actual tpl file is contained in the web application classpath. So, there are 2 projects, one 'taac-backend-api' and another 'taac-web'; taac-backend-api has the code to grab the template, and process it, but taac-web is where the template is stores (specifically in: WEB-INF/classes/email/vendor.tpl) - I have tried everything from using springs classpath resource to using Freemarkers setClassForTemplateLoading method. I assume this would work:
freemarkerConfiguration = new Configuration();
freemarkerConfiguration.setClassForTemplateLoading(this.getClass(), "");
Template freemarkerTemplate = freemarkerConfiguration.getTemplate("/email/vendor.tpl");
yet, I always get a FileNotFoundException. Can someone explain the best way to obtain a template from the classpath?
Thanks.
this is what ended up working for me:
freemarkerConfiguration = new Configuration(Configuration.VERSION_2_3_28);
freemarkerConfiguration.setClassForTemplateLoading(this.getClass(), "/");
Template freemarkerTemplate = freemarkerConfiguration.getTemplate("email/vendor.tpl");
In 2017, the following is deprecated:
Configuration conf = new Configuration();
We should pass freemarker.template.Version to the constructor:
Configuration conf = new Configuration(new Version(2, 3, 23));
conf.setClassForTemplateLoading(Application.class, "/views");
where the version numbers refer to the current version of FreeMarker.
The views directory is located in src/main/resources.
freemarkerConfiguration = new Configuration();
freemarkerConfiguration.setClassForTemplateLoading(this.getClass(), "");
Template freemarkerTemplate = freemarkerConfiguration.getTemplate("template.tpl");
Use this method to load the classes from the package where your class is located, so if your class is
org.foo.SomeClass the templates will be looked for in /org/foo in the classpath. This keeps your templates stored with the class that uses/loads them.
If you are using Struts 2 and the Conventions plugin, wuntee's solution doesn't seem to work: setClassForTemplateLoading in turn creates an instance of ClassTemplateLoader which doesn't find files in jars no matter what path prefix is specified.
Instead, create an instance of StrutsClassTemplateLoader. (I do this in a custom sub-class of FreemarkerManager in its getTemplateLoader method.) It takes no parameters, so presumably it just knows how Struts and Conventions do things.
Use the following config and place it in application properties.
spring.freemarker.template-loader-path=