I am setting up a dev, qa, staging, production system of deployment. I would like to be able to promote a release from one environment to the next without having to re-publish from VS, and without manually touching any files.
I need separate databases for DEV, QA and STG/PRO , so this would mean connection strings need to be switched dynamically according to the environment.
I could do this in a data layer -- perhaps something similar to this: Managing ASP.NET Development, Staging and Production Connection Strings (without pulling your hair out) -- but my data layer is built upon Entity Framework.
QUESTION: Is there a way to achieve dynamic switching of connection strings while using Entity Framework?
I am setting up a dev, qa, staging, production system of deployment. I
would like to be able to promote a release from one environment to the
next without having to re-publish from VS, and without manually
touching any files.
This is really strange and bad requirement. It is absolutely common to reconfigure application during deployment to different environment. Instead of hardcoding this in your application you should have different set of installation / deployment scripts which would also change your configuration file when moving from one environment to another.
Holding configuration for all environments in the configuration is IMHO very bad practice.
Even with hardcoded solution you still need to change some "configuration" to tell application which environment it currently runs on. Hardcoded solution will use information about environment to select correct connections string from configuration file and pass it to context constructor.
As example of the mentioned approach you can try this. It will still require you to change environment variable each time you redeploy application - complexity of such modification in custom deployment script is exactly the same as replacing connection string:
Configuration file:
<appSettings>
<add key="environment" value="Dev"/>
</appSettings>
<connectionStrings>
<add name="Dev" connectionString="..."/>
</connectionStrings>
Code for context factory method:
public static YourContext ContextFactory()
{
string environment = WebConfigurationManager.AppSettings["environment"].Value;
// This should be correctly recognized as a name of connection string.
return new YourContext(environment);
}
Context:
public class YourContext : DbContext
{
public YourContext(string connectionStringName) : base(connectionStringName)
{ }
}
Assuming that you are using a unit of work pattern; it means that your object context is recreated after every unit of work.
You likely have a class, that inherits from some sort of object context so in the constructor you use to create that context you can reference the base constructor that allows you to pass in a connection string.
From there, you can call a static method or new up an object to handle the creation of a connection string or pass in an entity connection.
If you are using a DbContext, it is the same, only with DbConnection instead of EntityConnection.
Related
I use WAS Liberty Server container which provides server.xml and server.env file for configuring many things in addition to configuring DataSource properties such as url, username, password etc.
For security reasons, these properties are not known to developers for production Liberty servers. However, developers use same server.xml/server.evn files but with different DataSource properties so they can do their work.
So, I might have two server.env files like:
PRODUCTION server.env: dataSourceUrl="server-A-URL" (this URL is not known to developers)
DEVELOPMENT server.env: dataSourceUrl="server-B-URL" (this URL is known to developers)
, then the dataSourceUrl is used in server.xml files in production and development to set the url accordingly.
So, the structure of server.xml/server.env file is same for developers and production, only the DataSource url, username, password are different. This way developers can work using their own DataSource properties and once ready to deploy they app, it is handed to other team which then just changes the DataSource properties to the production values and deploys the application to production server.
With Springboot JPA, I know we can use application.properties file to set these DataSource values. But, we would like to be able to set these to the values located in server.env file. Basically to have something like this in application.properties file:
spring.datasource.url=dataSourceUrl //dataSourceUrl is set in server.env
, then be able to use this value in Java code using #Value injection like:
public class MyClass {
#Value("${spring.datasource.url}")
String dsUrl;
...
}
I have been reading about externalizing properties but I am not able to figure out how to do this
You can use Liberty's jndiEntry elements to make configured values available in JNDI. You will need the jndi-1.0 feature, after which you can configure,
<jndiEntry jndiName="spring/datasource/url" value="${dataSourceUrl}"/>
and access it in your application as:
String dsUrl = InitialContext.doLookup("spring/datasource/url");
Or, from a web or ejb component as:
#Resource(lookup = "spring/datasource/url")
String dsUrl;
I am working with Spring and have information in my application.properties that I want to update from an HTML page
Myapplication.properties
...
spring.mail.host=smtp.gmail.com
spring.mail.port=587
...
Let say we need to change the port.
Is it possible to do something like that and what is the result if a user is logged in and we made a change?
I also read this post Update property in spring environment in java code is it the right solution.
I guess if I say that we need to rebuild the appplication.properties after changing some information.
Is it possible to do something like that and what is the result if a
user is logged in and we made a change?
if i understood it right, you want to change mail port in runtime? if so :
of course this is possible, but changing the value in property file alone wouldn't result in a actual change in your system, you should know that it is your responsibility to manage the reconstruction of a new mail sender instance in which you should also consider issues like multi-threading , race-condition , etc
I propose you to use application.properties in system startup to initialize your instance, and in case of change use something like this:
taking advatage of the Changing mail configuration in runtime and singleton pattern you should probabaly reach your aim :
#Component
public class MailSender{
#Value("${spring.mail.host}")
public static String host;
#Value("${spring.mail.port}")
private static Integer port
private static JavaMailSender instance;
public static synchronized JavaMailSender getInstance(Integer port) {
if (instance == null || port!= null) {
MailSender.port = port!=null ? port: MailSender.port;
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost(MailSender.host);
mailSender.setPort(MailSender.port);
return instance;
}
}
The above code is an alteration of singleton pattern in which we check whether the mail instance is null or port has new value recreate the instance otherwise if instance has already a value use that, in this way you can change port run time.
please notice that by the code above I am trying to give you some insight into the problem and you may change it based on your design.
I hope I got your purpose correctly.
First of all, after changing configuration you have to reload beans dependent on changed variables.
I would recommend you to have a look at Spring Cloud Config project.
It has the following features:
Stores configs (and changes) in Git
Can change configuration properties at runtime, and force subscribed applications to reload their context (or even dependent beans only) automatically
Despite it is not direct answer to your question (it doesn't have an UI for configuration), but it is a good reason to search UI for Spring Cloud Config instead.
I am new to Spring Boot and I am doing code cleanup for my old Spring Boot application.
Below code is using #Value annotation to inject filed value from properties file.
#Value("${abc.local.configs.filepath}")
private String LOCAL_ABC_CONFIGS_XML_FILEPATH;
My doubt is instead of getting value from properties file, can we not directly hardcode the value in same java class variable?
Example: private String LOCAL_ABC_CONFIGS_XML_FILEPATH="/abc/config/abc.txt"
It would be easier for me to modify the values in future as it will be in same class.
What is advantage of reading from properties file, does it make the code decoupled ?
This technique is called as externalising configurations. You are absolutely right that you can have your constants defined in the very same class files. But, sometimes, your configurations are volatile or may change with respect to the environment being deployed to.
For Example:
Scene 1:
I have a variables for DB connection details which will change with the environment. Remember, you will create a build out of your application and deploy it first to Dev, then take same build to stage and finally to the production.
Having your configurations defined externally, helps you to pre-define them at environment level and have same build being deployed everywhere.
Scene 2:
You have already generated a build and deployed and found something was incorrect with the constants. Having those configurations externalised gives you a liberty to just override it on environment level and change without rebuilding your application.
To understand more about externalising techniques read: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Here #value is used for reading the values from properties file (it could be a any environment like dev, qa, prod) but we are writing #value on multiple fields it is not recomonded so thats instead of #value we can use #configurableProperties(prefix="somevalue>) and read the property values suppose `
#configurableProperties(prefix="somevalue")
class Foo{
string name;
string address;
}
application.properties:
somevalue.name="your name"
somevalue.address="your address"
`
I have develop a new Connector. This connector requires to be configured with two parameters, lets say:
default_trip_timeout_milis
default_trip_threshold
Challenge is, I want read ${myValue_a} and ${myValue_a} from an API, using an HTTP call, not from a file or inline values.
Since this is a connector, I need to make this API call somewhere before connectors are initialized.
FlowVars aren't an option, since they are initialized with the Flows, and this is happening before in the Mule app life Cycle.
My idea is to create an Spring Bean implementing Initialisable, so it will be called before Connectors are init, and here, using any java based libs (Spring RestTemplate?) , call API, get values, and store them somewhere (context? objectStore?) , so the connector can access them.
Make sense? Any other ideas?
Thanks!
mmm you could make a class that will create the properties in the startup and in this class obtain the API properties via http request. Example below:
public class PropertyInit implements InitializingBean,FactoryBean {
private Properties props = new Properties();
#Override
public Object getObject() throws Exception {
return props;
}
#Override
public Class getObjectType() {
return Properties.class;
}
}
Now you should be able to load this property class with:
<context:property-placeholder properties-ref="propertyInit"/>
Hope you like this idea. I used this approach in a previous project.
I want to give you first a strong warning on doing this. If you go down this path then you risk breaking your application in very strange ways because if any other components depend on this component you are having dynamic components on startup, you will break them, and you should think if there are other ways to achieve this behaviour instead of using properties.
That said the way to do this would be to use a proxy pattern, which is a proxy for the component you recreate whenever its properties are changed. So you will need to create a class which extends Circuit Breaker, which encapsulates and instance of Circuit Breaker which is recreated whenever its properties change. These properties must not be used outside of the proxy class as other components may read these properties at startup and then not refresh, you must keep this in mind that anything which might directly or indirectly access these properties cannot do so in their initialisation phase or your application will break.
It's worth taking a look at SpringCloudConfig which allows for you to have a properties server and then all your applications can hot-reload those properties at runtime when they change. Not sure if you can take that path in Mule if SpringCloud is supported yet but it's a nice thing to know exists.
I have a solution with multiple project using the same domain model. I thus created a class library that holds my domain models. This class library also contains other parameters that are used within my projects. I then add the reference to the class library in each of my projects.
My class library also has some repository classes derived from this example.
I however have an issue with connecting to a database. I want my class library to be able to connect to the database since I defined my database context class in there, where I set my database sets. With a single project, I usually define my connection string in my web.config file. But the class library has no web.config file. How do I set my connection string?
EDIT
Say i have the constructor of my database context, mydbcontext, defined in the class library as
public mydbcontext() : base(ConfigurationManager.ConnectionStrings["DatabaseCon"].ConnectionString)
{
}
If I understanding this right, will it be OK to just set the name of the connection string of each project to "DatabaseCon"?
You don't.
Pass in the connection string as a dependency to whatever classes that require it.
You can encapsulate the access to it - but you should instantiate it in whatever program that uses this library. This program will hold the connection string in its configuration.
You should define the connection string in the web.config file of the application that is using the class library. As an alternative you could hardcode the connection string into the constructor of your DbConext inside the class library - pretty bad approach because you won't be able to modify it from the outside - for example you will have hard time managing different connection strings for the different environments - staging, production, ...