Change the connection string of nopCommerce? - connection-string

I am using nopCommerce and I need to remove the connection string in the settings.txt file and insert the web.config file. How can i do this?

The most straightforward way to move the connection string out of settings.txt and into the web.config is to modify the Nop.Core.Data.DataSettingsManager. Specifically the LoadSettings() and SaveSettings() methods. You can store the connection string wherever you'd like (ideally in web.config), as long as those two methods read and write the configuration.
A rough example of the DataSettingsManager updated to support storing the connection string in web.config can be found in this Gist: http://git.io/vUPcI Just copy the connection string from settings.txt to web.config and name the connection "DefaultConnection" or adapt the code accordingly.

Just do two steps
Replace two method LoadSettings and SaveSettings in \nopCommerce\Libraries\Nop.Core\Data\DataSettingsManager.cs. Code from link of #Stephen Kiningham
/// <summary>
/// Load settings
/// </summary>
/// <param name="filePath">File path; pass null to use default settings file path</param>
/// <returns></returns>
public virtual DataSettings LoadSettings(string filePath = null)
{
try
{
System.Configuration.Configuration webConfig = WebConfigurationManager.OpenWebConfiguration(HttpRuntime.AppDomainAppVirtualPath);
return new DataSettings
{
DataConnectionString = webConfig.ConnectionStrings.ConnectionStrings["DefaultConnection"].ConnectionString,
DataProvider = webConfig.ConnectionStrings.ConnectionStrings["DefaultConnection"].ProviderName
};
}
catch (NullReferenceException)
{
return new DataSettings();
}
}
/// <summary>
/// Save settings to a file
/// </summary>
/// <param name="settings"></param>
public virtual void SaveSettings(DataSettings settings)
{
if (null == settings) throw new ArgumentNullException("settings");
System.Configuration.Configuration webConfig = WebConfigurationManager.OpenWebConfiguration(HttpRuntime.AppDomainAppVirtualPath);
webConfig.ConnectionStrings.ConnectionStrings["DefaultConnection"].ConnectionString = settings.DataConnectionString;
webConfig.ConnectionStrings.ConnectionStrings["DefaultConnection"].ProviderName = settings.DataProvider;
webConfig.Save();
}
Add connection string to your web config web.config
<connectionStrings>
<add name="DefaultConnection"
connectionString=" Data Source=localhost;Initial Catalog=nopcommerce;Integrated Security=True;Persist Security Info=False"
providerName="sqlserver">
</add>
</connectionStrings>

[1] In .NET Core (3.1 | NopCommerce 4.3) I created various appsettings.json files (including appsettings.json, appsettings.Development.json, appsettings.Integration.json, appsettings.Staging.json) and logic (beyond this discuss) determines the the correct settings to be used in the proper environment etc.
[2] \nopCommerce\Libraries\Nop.Core\Data\DataSettingsManager.cs
I created the following method:
public static string GetConnectionString()
{
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
string appSettingsFileName = env switch
{
"Development" => "appsettings.Development.json",
"Production" => "appsettings.json",
"Staging" => "appsettings.Staging.json",
"Integration" => "appsettings.Integration.json",
_ => "appsettings.json",
};
IConfigurationRoot configuration = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile(appSettingsFileName).Build();
string connectionString = configuration.GetConnectionString("DefaultConnection");
return connectionString;
}
(returns the proper connection string for the proper environment)
[3] In LoadSettings -- I didn't change anything to get down to the line
Singleton<DataSettings>.Instance = JsonConvert.DeserializeObject<DataSettings>(text);
... I just added a new line below to replace the .ConnectionString with the connectionstring determined from our new method:
Singleton<DataSettings>.Instance.ConnectionString = GetConnectionString();
important:
When I ran it there were three or four places where there was a switch (case > default:) that was looking for a provider etc -- But I just copied the settings from MsSql down to the default: and it worked fine. I know this is sloppy but I am never using MySql for this project and so far as I am concerned its a non-issue. Either way - I broke it to make it work (multiple Azure App environments are more important).
I suggest they should have built it the regular way and just provided us with a SQL script for deployment (over engineered a non-issue?) since we usually have to do that anyway for custom development (seems silly to me to hard code a data settings file in App_Data) - but I trust their logic.

Please add this to your web.config under Nop.Web project :
<connectionStrings>
<add name="MyConnectionString"
connectionString="Data Source=serverName;Initial Catalog=DBName;Persist Security Info=False;UserID=userName;Password=password"
</connectionStrings>
Best Regards.

In addition to adding the connection to the web.config, you have to specify the providerName="sqlserver".
Ex) ;Initial Catalog=;Integrated
Security=False;User ID=;Password=;Connect
Timeout=30;Encrypt=True"
providerName="sqlserver" />
This is because the EfDataProviderManager in Nop.Data has a check for the provider name, and will throw an exception if you put the normal
providerName="System.Data.SqlClient"

Related

Easily switching between connection strings in .NET Core

I've got a code base that uses EF Core and Dapper to perform actions on a database.
I want to set up a new copy of the site to develop some features and I want this site to connect to a new isolated copy of the database (dbConnectionDEBUG).
At the moment, I use the following setup:
startup.cs
...
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("dbConnectionMain")));
services.Configure<ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));
...
I have a ConnectionStrings class which is being populated correctly via the DI in startup:
public class ConnectionStrings
{
public string dbConnectionMain { get; set; }
public string dbConnectionDEBUG { get; set; }
public ConnectionStrings()
{
this.dbConnectionMain = "";
this.dbConnectionDEBUG = "";
}
}
Then, throughout my controllers/services I have access to ConnectionStrings and 99% of the time I'm doing the following to make DB calls:
using (var conn = new SqlConnection(_connectionStrings.dbConnectionMain))
{
conn.Open();
...
This would amount to a lot of code changes if I were to want to switch over to the 'DEBUG' db.
How do I easily switch between the connection strings in my code depending on what version of the system I'm working on.
If I could somehow do this dynamically that'd be great. The obvious determining factor would be the URL the site is operating on.
Alternatively, (as a single change) do I just manually change the connection string at the source (e.g keystore/appsettings). I'm not keen on this as it leaves room for human error.
Update (2)
Based on what #Nkosi mentioned I am pursuing this path:
Have one connection string 'Id' (i.e. dbConnection) used throughout
Differentiate the connection string value within this based on the environment the app is running/deployed in
I have another question:
If I have the following...
"MYAPPNAME": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:12345/;https://myapptestdomain.com/"
}
and:
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) =>
{
IHostingEnvironment env = context.HostingEnvironment;
config.AddJsonFile($"appsettings.{env.EnvironmentName.ToLower()}.json", optional: true);
})
.UseStartup<Startup>();
...will this automatically pick up my site is in the Development mode based on the applicationUrl values OR will I have to manually add ASPNETCORE_ENVIRONMENT with a value Development on the server I deploy the app to?
Additional: My app is running in an Azure App Service.
Update (3) - Mission Complete
Just to finalise this question (in case anyone needs to know this), I have the following setup based on recommendations made by #Nkosi.
Connection String - I have one connection string Id/name dbConnection which is used in all appSettings (see below)
App Settings
I have a default appSettings.json with dbConnection that looks at the live database
I have an additional appSettings.Playground.json file with dbConnection that looks at my testing database
Azure - App Service - On my playground development slot I have added an App Setting for ASPNETCORE_ENVIRONMENT with the value 'Playground'
In my Program.cs file I have:
config.AddJsonFile($"appsettings.json", optional: true,reloadOnChange: true);
and
config.AddJsonFile($"appsettings.{env.EnvironmentName.ToLower()}.json", optional: true,reloadOnChange: true);
Just to note, I do also initialise a Vault on Azure which stores all my Keys and Secrets for the Azure based apps. Locally User Secrets is used.
ASP.NET Core reads the environment variable ASPNETCORE_ENVIRONMENT at app startup and stores the value in IHostingEnvironment.EnvironmentName.
Since the environment is being loaded, then it should be available from the hosting environment via the builder context
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) => {
string environment = context.HostingEnvironment.EnvironmentName; //get current environment
//load config based on environment.
config.AddJsonFile($"appsettings.{environment}.json", optional: true);
//...
})
//...
Reference Use multiple environments in ASP.NET Core
For simple apps and to keep the connection strings away from my repository I use preprocessor statements plus PATH/System Variables and for release I provide a connection string within the settings.json.
#define USE_FEATURE_X
using System;
namespace MyNamespace {
internal static class StaticConnectionStringFactory {
public static string GetConnectionString() {
#if DEBUG && !USE_FEATURE_X
var connectionString = Environment.GetEnvironmentVariable("CNNSTR_SQL_XYZ", EnvironmentVariableTarget.User);
#elif DEBUG && USE_FEATURE_X
var connectionString = Environment.GetEnvironmentVariable("CNNSTR_SQL_ABC", EnvironmentVariableTarget.User);
#else
var connectionString = Environment.GetEnvironmentVariable("SqlConnectionString", EnvironmentVariableTarget.Process);
#endif
return connectionString;
}
}
}
I think if you add 2 connection for debug and main then you will have face some difficulty because more member working in you team. may be some own wrongly use release mode for code development.
you can try this webconfig method:
public class ConnectionStrings
{
public string dbConnection { get; set; }
public ConnectionStrings()
{
bool Ismain = bool.Parse(System.Configuration.ConfigurationManager.AppSettings["HasLive"]);
if (Ismain)
{
dbConnection = "";// get Main connectionstring
}
else
{
dbConnection = "";// get Debug connectionstring
}
}
}
web.config:
<connectionStrings>
<add name="dbConnectionMain" connectionString="" providerName="System.Data.SqlClient" />
<add name="dbConnectionDEBUG" connectionString="" roviderName="System.Data.SqlClient" />
</connectionStrings>
<appSettings>
<add key="HasLive" value="false"/>
</appSettings>
</connectionStrings>

Why did my Visual Studio 10 stop using App.Config for my SQL connection string?

I have a working database application using WPF and SQL Server 2008 R2, which for two years has been getting its SQL Server connection string from the App.Config file. A few days ago on one dev machine, it started ignoring the App.Config file's connectionString, and is now using a string from somewhere else (looks like either settings.settings, or the DBML file).
Why might this be happening, and how can I get it to stop doing that?
The app.config starts out like this:
<configuration>
<configSections>
<section name="log4net" type="System.Configuration.IgnoreSectionHandler"/>
</configSections>
<connectionStrings>
<add name="DronzApp.Properties.Settings.DronzAppConnectionString"
connectionString="Server=dronz.db.123.dronzdbserver.com;Database=dronzdb;User ID=dronz;Password=secretsauce;"
providerName="System.Data.SqlClient" />
</connectionStrings>
Edit: Thanks for the suggestions from both of you for more info and where to look. I don't know where a WPF App gets the information that it ought to look in App.Config, or anyplace else, but until I learn that, here are some more pieces:
One of the first things my program does is test the database (which now fails). Right before it does that, it calls the auto-generated function InitializeComponent(), whose auto-generated code is:
/// <summary>
/// InitializeComponent
/// </summary>
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public void InitializeComponent() {
if (_contentLoaded) {
return;
}
_contentLoaded = true;
System.Uri resourceLocater = new System.Uri("/DronzApp;component/ui/startwindow.xaml", System.UriKind.Relative);
#line 1 "..\..\..\UI\StartWindow.xaml"
System.Windows.Application.LoadComponent(this, resourceLocater);
#line default
#line hidden
}
My start window constructor calls InitializeComponent(); and then tests the database with the line:
int hmm = App.db.Dronz_FooTable.Count();
where App.db is a data context defined in the app.xaml.cs file as:
public static DronzDataDataContext db = new DronzDataDataContext();
where DronzDataDataContext is defined in auto-generated code by LINQ-to-SQL such as:
public partial class DronzDataDataContext : System.Data.Linq.DataContext
...
public DronzDataDataContext() :
base(global::DronzApp.Properties.Settings.Default.DronzConnectionString, mappingSource)
{
OnCreated();
}
Which used to heed the app.config file, and now doesn't. When I catch the DB exception (which is about a DB version problem because it is trying to use the wrong SQL server) and look at the connection string, it is asking the wrong SQL Server for a file instead of the correct connection string. The connection string it is using seems to match either the DBML file that Linq-to=SQL created when the database schema was imported, or a string in settings.settings (which is a file I don't really understand where it came from or what I'm supposed to do or not do with it).
Ok, I seem to have found and fixed the problem, but I don't know what caused it, exactly.
What references the Config file is actually in the .proj file, and somehow it changed to add a reference to app.config at the project root instead of in an App subfolder. From reading other discussion of app.config, I think VS2010 did this automatically perhaps when I was looking at the Project settings in the GUI. Deleting that line of XML manually from the .proj file allowed it to find and use the previous version which points to where the app.config file actually is. Since I didn't have an app.config file in the project root where the new first line was edited to say it was in the .proj file, it seems to have fallen to looking at settings.settings, where it found the connectionString value where the file was when I imported the database file using Linq to SQL.

What can I do to generate the DB in EF Code First?

I am not planning to use EF Code First in an MVC Website. I am looking to Utilize it in a App that has a WPF Client.
Projects are setup as
ContactManager.Core // Contains all
Entities(dll)
ContactManager.Data // Contains
the DataContext and other data
related Services(dll)
ContactManager.Services // Business
components (dll)
ContactManager.Client // WPF
Application
I am unable to generate a SQLExpress or SQLCE 4.0 DB. I am more interested in compact version db. I am not getting any error except my unit tests fail because it tries to connect a db that doesnt exist.
I found out the answer 2 Options:
Option 1:
In your DbContext you specify the connection strings in the base constructor:
public class RecetteContext : DbContext
{
public RecetteContext()
:base("<YourConnectionString HERE>")
{
}
public DbSet<Categorie> Categories { get; set; }
public DbSet<Recette> Recettes { get; set; }
}
}
Option 2:
The one I used, you give you connection string a name in the DbContext base constructor:
public RecetteContext()
: base("RecettesDatabase")
{ }
And in your App.Config file you add a ConnectionString with the same name:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="RecettesDatabase"
connectionString="Data Source=RecettesDB.sdf"
providerName="System.Data.SqlServerCe.4.0"/>
</connectionStrings>
</configuration>
Hope it solved your issue!

DB connection strings in MVC applications using Entity Framework

I am working on an MVC application using Entity Framework.
After creating an EDMX, I noticed the DB connection string is located in TWO places - an app.config file in my Data class library, and a web.config file in my web application.
We want to:
remove these two plain text connection strings
encrypt a single connection string
and use our pre-existing class library to decrypt the connection string when needed
I tried removing one or the other connection string from the config files, and DB access fails. Why are TWO required? And is there any way to do what we want in an MVC - EF project, and how would I tell EF that is what we are doing?
Thanks!
You can ignore the connection string in your EF project, I think, and just set the connection programmatically from your controller.
public class SomeController : Controller
{
public SomeController()
{
/* Substitute whatever method you want to fetch your data source string here */
/* example assumes plain text from web.config */
string dataSource = ConfigurationManager
.ConnectionStrings["ApplicationServices"]
.ConnectionString;
this.Entities = new SomeEntities(dataSource);
}
private SomeEntities Entities { get; set; }
}

How to edit an external web.config file?

I am trying to write a winform application that would be able to edit the web.config file of an installed web application.
I have read through the ConfigurationManager and WebConfigurationManager class methods but I am unsure as to how I can open the configuration file of a web app and edit it.
I am looking for a method that does not require me to load the config file as a regular XmlDocument, although I am willing to do that if that is the only option available.
Any advice would be appreciated.
Ok so here is the answer, I have the EXACT same scenario. I wanted to write a winforms app to allow normal users to update the web.config. You have to go about getting the config a goofy way...
// the key of the setting
string key = "MyKey";
// the new value you want to change the setting to
string value = "This is my New Value!";
// the path to the web.config
string path = #"C:\web.config";
// open your web.config, so far this is the ONLY way i've found to do this without it wanting a virtual directory or some nonsense
// even "OpenExeConfiguration" will not work
var config = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap() { ExeConfigFilename = path }, ConfigurationUserLevel.None);
// now that we have our config, grab the element out of the settings
var element = config.AppSettings.Settings[key];
// it may be null if its not there already
if (element == null)
{
// we'll handle it not being there by adding it with the new value
config.AppSettings.Settings.Add(key, value);
}
else
{
// note: if you wanted to you could inspect the current value via element.Value
// in this case, its already present, just update the value
element.Value = value;
}
// save the config, minimal is key here if you dont want huge web.config bloat
config.Save(ConfigurationSaveMode.Minimal, true);
Here is an example of what it does
Before:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="MyKey" value="OldValue" />
</appSettings>
<connectionStrings>
<add name="myConnString" connectionString="blah blah blah" providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
After:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="MyKey" value="This is my New Value!" />
</appSettings>
<connectionStrings>
<add name="myConnString" connectionString="blah blah blah" providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<trust level="Full" />
<webControls clientScriptsLocation="/aspnet_client/{0}/{1}/" />
</system.web>
</configuration>
Just be careful, if you give it an invalid path, it will just create a config file at that path / filename. Basically, do a File.Exists check on it first
BTW, while you're at it, you could write a class that represents your settings in your web.config. Once you do this, write your getters/setters to read/write the settings in the web.config. Once THIS is done, you can add this class as a datasource and drag the databound controls onto your winform. This will give you a completely databound winform web.config editor that you can easily hammer out in a matter of minutes. I've got an example at work that I'll post tomorrow.
Fully featured winforms solution
So this is a relatively simple solution to writing a Gui to edit a web.config, some may say its overly complicated when notepad will do just fine but it works for me and my audience.
It basically works as described above, I wrote a class that had the configuration points that I wanted as properties. The ctor opens the file from a path and the getters / setters pull the data out of the returned configuration object, finally it has a save method that writes it out. With this class, I'm able to add the class as a datasource and drag / drop bound controls onto winforms. From there all you have to do is to wire up a button that calls the save method on your class.
Configuration class
using System.Configuration;
// This is a representation of our web.config, we can change the properties and call save to save them
public class WebConfigSettings
{
// This holds our configuration element so we dont have to reopen the file constantly
private Configuration config;
// given a path to a web.config, this ctor will init the class and open the config file so it can map the getters / setters to the values in the config
public WebConfigSettings(string path)
{
// open the config via a method that we wrote, since we'll be opening it in more than 1 location
this.config = this.OpenConfig(path);
}
// Read/Write property that maps to a web.config setting
public string MySetting
{
get { return this.Get("MySetting"); }
set { this.Set("MySetting", value); }
}
// Read/Write property that maps to a web.config setting
public string MySetting2
{
get { return this.Get("MySetting2"); }
set { this.Set("MySetting2", value); }
}
// helper method to get the value of a given key
private string Get(string key)
{
var element = config.AppSettings.Settings[key];
// it may be null if its not there already
if (element == null)
{
// we'll handle it not being there by adding it with the new value
config.AppSettings.Settings.Add(key, "");
// pull the element again so we can set it below
element = config.AppSettings.Settings[key];
}
return element.Value;
}
// helper method to set the value of a given key
private void Set(string key, string value)
{
// now that we have our config, grab the element out of the settings
var element = this.config.AppSettings.Settings[key];
// it may be null if its not there already
if (element == null)
{
// we'll handle it not being there by adding it with the new value
config.AppSettings.Settings.Add(key, value);
}
else
{
// in this case, its already present, just update the value
element.Value = value;
}
}
// Writes all the values to the config file
public void Save()
{
// save the config, minimal is key here if you dont want huge web.config bloat
this.config.Save(ConfigurationSaveMode.Minimal, true);
}
public void SaveAs(string newPath)
{
this.config.SaveAs(path, ConfigurationSaveMode.Minimal, true);
// due to some weird .net issue, you have to null the config out after you SaveAs it because next time you try to save, it will error
this.config = null;
this.config = this.OpenConfig(newPath);
}
// where the magic happens, we'll open the config here
protected Configuration OpenConfig(string path)
{
return ConfigurationManager.OpenMappedExeConfiguration(
new ExeConfigurationFileMap() { ExeConfigFilename = path },
ConfigurationUserLevel.None);
}
}
Build and then from there you can just goto your winform designer, goto Data > Show Data Sources (Shift+Alt+D). Right click > Add New Data Source and add it as an object as shown
Data Source Configuration Wizard 1 of 2 http://img109.imageshack.us/img109/8268/98868932.png
Data Source Configuration Wizard 2 of 2 http://img714.imageshack.us/img714/7287/91962513.png
Drag it (WebConfigSettings, the topmost) onto the winform. In my case, I will remove the navigator as that is for a List and I just have one.
Freshly added databound controls http://img96.imageshack.us/img96/8268/29648681.png
You should have something like webConfigSettingsBindingSource at the bottom of the designer (shown in the next pic). Goto the code view and change the ctor to this
public Form1()
{
InitializeComponent();
// wire up the actual source of data
this.webConfigSettingsBindingSource.DataSource = new WebConfigSettings(#"c:\web.config");
}
Add a save button to your winform
Save button added http://img402.imageshack.us/img402/8634/73975062.png
Add the following event handler
private void saveButton_Click(object sender, EventArgs e)
{
// get our WebConfigSettings object out of the datasource to do some save'n
var settings = (WebConfigSettings)this.webConfigSettingsBindingSource.DataSource;
// call save, this will write the changes to the file via the ConfigurationManager
settings.Save();
}
There, now you have a nice simple databound web.config editor. To add / remove fields, you just modify your WebConfigSettings class, refresh the datasource in the Data Sources window (after a build), and then drag n drop the new fields onto the UI.
You'll still have to wire up some code that specifies a web.config to open, for this example I just hard coded the path.
The cool thing here is all the value that a GUI adds. You can easily add directory or filebrowser dialogs, you can have connection string testers etc. All are very easy to add and very powerful to the end user.
I highly recommend you to use XElement along with LINQ enabled (LINQ to XML).
For instance you want to change the connectionString. This type of code is good enough
var connString = from c in webConfigXElement.appSettings.connectionString
where c.name == "myConnection"
select c;
and now you have full control over the <connectionString /> element, and do whatever you want to do with it.
I am referring you to MSDN for learning and also a Kick Start for instant working.
Hope this helps you to have full control over your .xml without pain.
Here you go, I wrote a toy app (VB.NET Windows client) that edits XML files using a Tree / Grid for navigating and editing.
You might get some ideas from it. The VS project file for it is here or just an MSI to install it is here, if you want to try it out on your web.config.
It loads the file into a DataSet (DataSet.ReadXML()) which parses it into DataTables, then displays and allows editing of the contents in a standard DataGrid. Then it will save the edited content back to the XML file (DataSet.WriteXML()).
All app.config and web.config are just XML files. You can open and edit them using XMLDocument, XMLWriter, etc.

Resources