change entity connection on the fly - c#

I am using C# 4.0. (Winform Application)
I have a code like this:
private bool ChangeEFConnectionString(string connStringName, string newValue)
{
try
{
//CreateXDocument and load configuration file
XDocument doc = XDocument.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
//Find all connection strings
var query1 = from p in doc.Descendants("connectionStrings").Descendants()
select p;
//Go throught each connection string elements find atribute specified by argument and replace its value with newVAlue
foreach (var child in query1)
{
foreach (var atr in child.Attributes())
{
if (atr.Name.LocalName == "name" && atr.Value == connStringName)
if (atr.NextAttribute != null && atr.NextAttribute.Name == "connectionString")
{
// Create the EF connection string from existing
EntityConnectionStringBuilder entityBuilder =
new EntityConnectionStringBuilder(atr.NextAttribute.Value);
//change hte provide conn string
entityBuilder.ProviderConnectionString = newValue;
//back the full connection string to the configuration fiel
atr.NextAttribute.Value = entityBuilder.ToString();
}
}
}
doc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
It works well, but somehow it not work any more.
As I debug it : entityBuilder.ProviderConnectionString = newValue; had the right value
but it still not change the connectionstring.

Use ConfigurationManager for reading and updating connection strings:
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.ConnectionStrings.ConnectionStrings[connStringName].ConnectionString = newValue;
config.Save(ConfigurationSaveMode.Modified, true);
ConfigurationManager.RefreshSection("connectionStrings");

I think all you need is, after the Save, a:
ConfigurationManager.RefreshSection("connectionStrings");
Have you considered giving EF the whole connection string instead of the name? That would keep you from having to modify what the name means at run time.

Related

MongoDB Change Stream

I try to code a MongoDB change stream. But if I do some changes, my code doesn't detect the changes. If the code detects the changes I have to get the operation type - according to my understanding. Moreover, how can I insert the changes in the other database? Is it so "easy", that I code a new database connection and update/insert/delete the collection/database?
What did I Code?
`
lang-cs
string mongo_db_client = "mongodb://localhost:27017";
string m_database = "myDataBase";
string m_collection ="myCollection";
MongoClient dbClient = new MongoClient(mongo_db_client);
var database = dbClient.GetDatabase(m_database);
var collection = database.GetCollection<BsonDocument>(m_collection);
var cursor = collection.Watch();
var the_operation_type = null;
if(cursor != null)
{
using(cursor)
{
var curr = cursor.Current;
if (curr != null)
{
foreach (var change in curr)
{
try
{
the_operation_type= change.OperationType;
}
catch(NullReferenceException e)
{
Log(e.ToString());
}
}
}
}
}
`

save multiple key/value pairs to app.config

I'm working on an winform application, where I store some setting (username, email, zipcode) in the app.config file.
public static void Set(string key, string value)
{
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var entry = config.AppSettings.Settings[key];
if (entry == null)
config.AppSettings.Settings.Add(key, value);
else
config.AppSettings.Settings[key].Value = value;
config.Save(ConfigurationSaveMode.Modified);
}
I'd like to save the settings to the app.config file. So I have this code.
Problem is: I can only use the variable key once.... So i can't saven the email and zipcode.
I was thinking of working with an array, but I have no idea on how to implement this. Any suggestions?
private void button_savesettings_Click(object sender, EventArgs e)
{
string key = "username";
string username = textBox_user.Text;
Set(key, username);
}
Many thanks!
A simple loop will solve the problem
void SetAppSettingsValues(Dictionary<string, string> dict)
{
// bit of validation
if (dict == null || !dict.Any())
return;
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
foreach (var key in dict.Keys)
{
var configItem = config.AppSettings.Settings[key];
if (configItem == null)
config.AppSettings.Settings.Add(key, dict[key].Value);
else
config.AppSettings.Settings[key].Value = dict[key].Value;
}
config.Save(ConfigurationSaveMode.Modified);
}
The better way is to use SQLite for Winform.
Saving things to app.config could be messy when your data variable grows bigger.

Why doesn't SMO scripter generate foreign key headers?

I'm creating a program to generate my database schema using the SMO libraries distributed with SQL Server 2008.
I've gotten the scripter outputting code which is virtually the same as SQL Server Management Studio outputs when it's configured to output everything, but with one curious exception: it doesn't output comment headers for the foreign key constraints it generates at the bottom, whereas SSMS does. Can anyone figure out why this is? Here's my code:
private void btnExportScript_Click(object sender, EventArgs ea) {
Server srv = setupConnection();
// Reference the database
if (!srv.Databases.Contains(cbChooseDb.SelectedItem.ToString())) {
_utils.ShowError("Couldn't find DB '" + cbChooseDb.SelectedItem.ToString() + "'.");
return;
}
Database db = srv.Databases[cbChooseDb.SelectedItem.ToString()];
StringBuilder builder = new StringBuilder();
try {
Scripter scrp = new Scripter(srv);
scrp.Options.AppendToFile = false;
scrp.Options.ToFileOnly = false;
scrp.Options.ScriptDrops = false; // Don't script DROPs
scrp.Options.Indexes = true; // Include indexes
scrp.Options.DriAllConstraints = true; // Include referential constraints in the script
scrp.Options.Triggers = true; // Include triggers
scrp.Options.FullTextIndexes = true; // Include full text indexes
scrp.Options.NonClusteredIndexes = true; // Include non-clustered indexes
scrp.Options.NoCollation = false; // Include collation
scrp.Options.Bindings = true; // Include bindings
scrp.Options.SchemaQualify = true; // Include schema qualification, eg. [dbo]
scrp.Options.IncludeDatabaseContext = false;
scrp.Options.AnsiPadding = true;
scrp.Options.FullTextStopLists = true;
scrp.Options.IncludeIfNotExists = false;
scrp.Options.ScriptBatchTerminator = true;
scrp.Options.ExtendedProperties = true;
scrp.Options.ClusteredIndexes = true;
scrp.Options.FullTextCatalogs = true;
scrp.Options.SchemaQualifyForeignKeysReferences = true;
scrp.Options.XmlIndexes = true;
scrp.Options.IncludeHeaders = true;
// Prefectching may speed things up
scrp.PrefetchObjects = true;
var urns = new List<Urn>();
// Iterate through the tables in database and script each one.
foreach (Table tb in db.Tables) {
if (tb.IsSystemObject == false) {
// Table is not a system object, so add it.
urns.Add(tb.Urn);
}
}
// Iterate through the views in database and script each one. Display the script.
foreach (Microsoft.SqlServer.Management.Smo.View view in db.Views) {
if (view.IsSystemObject == false) {
// View is not a system object, so add it.
urns.Add(view.Urn);
}
}
// Iterate through the stored procedures in database and script each one. Display the script.
foreach (StoredProcedure sp in db.StoredProcedures) {
if (sp.IsSystemObject == false) {
// Procedure is not a system object, so add it.
urns.Add(sp.Urn);
}
}
// Start by manually adding DB context
builder.AppendLine("USE [" + db.Name + "]");
builder.AppendLine("GO");
System.Collections.Specialized.StringCollection sc = scrp.Script(urns.ToArray());
foreach (string st in sc) {
// It seems each string is a sensible batch, and putting GO after it makes it work in tools like SSMS.
// Wrapping each string in an 'exec' statement would work better if using SqlCommand to run the script.
builder.Append(st.Trim(new char[] { '\r', '\n' }) + "\r\nGO\r\n");
}
}
catch (Exception ex) {
showExceptionError("Couldn't generate script.", ex);
return;
}
try {
File.WriteAllText(txtExportToFile.Text, builder.ToString());
_utils.ShowInfo("DB exported to script at: " + txtExportToFile.Text);
}
catch (Exception ex) {
showExceptionError("Couldn't save script file.", ex);
return;
}
}
Note that foreign keys fall under the category of DRI constraints, and are scripted because of scrp.Options.DriAllConstraints = true;.
I have a solution here: Can't get EnumScript() to generate constraints
for some reason, Scripter won't emit DRI constraints (foreign keys, etc) when it's given a list of Urns, but it will if it's given one Urn at a time. The trick there is to give the Urns in the order of their ancestry: tables have to be defined before they're referenced by constraints. To do that I've used the DependencyWalker.
Here's a synopsis:
var urns = new List<Urn>();
Scripter schemaScripter = new Scripter(srv) { Options = schemaOptions };
Scripter insertScripter = new Scripter(srv) { Options = insertOptions };
var dw = new DependencyWalker(srv);
foreach (Table t in db.Tables)
if (t.IsSystemObject == false)
urns.Add(t.Urn);
DependencyTree dTree = dw.DiscoverDependencies(urns.ToArray(), true);
DependencyCollection dColl = dw.WalkDependencies(dTree);
foreach (var d in dColl)
{
foreach (var s in schemaScripter.Script(new Urn[] { d.Urn }))
strings.Add(s);
strings.Add("GO");
if (scriptData)
{
int n = 0;
foreach (var i in insertScripter.EnumScript(new Urn[] {d.Urn}))
{
strings.Add(i);
if ((++n) % 100 == 0)
strings.Add("GO");
}
}
}
Note: adding a "GO" every so often keeps the batch size small so SSMS doesn't run out of memory.

Passing ConnectionString from SqlConnectionSringBuilder to ConnectionManager

I want to get a ConnectionString from an instance of SqlConnectionStringBuilder as a String.
This seems simple, and should be as easy as this:
String conString = builder.ConnectionString;
However the String that SqlConnectionStringBuilder gives up doesn't include the Password field/value. I'm guessing this is some sort of security feature, is there a way to force Password to be included in the String?
Looking at this further I'm thinking this may have something to do with ConnectionManager. What I am trying to do is modify the ConnectionString for a Package, changing the Initial Catalog.
Below is my code, the point that builder's connection string is passed back into connectionManager's the Password is lost...
public void DataTransfer(String sourceConnection, String destConnection, String pkgLocation)
{
Package pkg;
Application app;
DTSExecResult pkgResults;
try
{
app = new Application();
pkg = app.LoadPackage(pkgLocation, null);
foreach (ConnectionManager connectionManager in pkg.Connections)
{
SqlConnectionStringBuilder builder;
switch (connectionManager.Name)
{
case "SourceConnection":
builder = new SqlConnectionStringBuilder(sourceConnection) { PersistSecurityInfo = true };
builder.Remove("Initial Catalog");
builder.Add("Initial Catalog", "StagingArea");
connectionManager.ConnectionString = builder.ConnectionString.ToString();
connectionManager.ConnectionString += ";Provider=SQLNCLI;Auto Translate=false;";
Debug.WriteLine(connectionManager.ConnectionString.ToString());
break;
case "DestinationConnection":
builder = new SqlConnectionStringBuilder(sourceConnection) { PersistSecurityInfo = true };
builder.Remove("Initial Catalog");
builder.Add("Initial Catalog", "StagingArea");
connectionManager.ConnectionString = builder.ConnectionString.ToString();
connectionManager.ConnectionString += ";Provider=SQLNCLI;Auto Translate=false;";
Debug.WriteLine(connectionManager.ConnectionString.ToString());
break;
}
}
pkgResults = pkg.Execute();
}
catch (Exception e)
{
throw;
}
Console.WriteLine(pkgResults.ToString());
}
Set PersistSecurityInfo to True before setting other properties in the SqlConnectionStringBuilder : D
I need to rename this a little maybe, as the question is different now, but here is my solution:
The first part of this question was answered correctly by #madd0. The ConnectionString does contain the Password field.
The second part was solved with formatting code is below:
public void DataTransfer(String sourceConnection, String destConnection, String pkgLocation)
{
Package pkg;
Application app;
DTSExecResult pkgResults;
try
{
app = new Application();
pkg = app.LoadPackage(pkgLocation, null);
foreach (ConnectionManager connectionManager in pkg.Connections)
{
SqlConnectionStringBuilder builder;
switch (connectionManager.Name)
{
case "SourceConnection":
builder = new SqlConnectionStringBuilder(sourceConnection) { PersistSecurityInfo = true };
builder.Remove("Initial Catalog");
builder.Add("Initial Catalog", "StagingArea");
var sourceCon = builder.ConnectionString + ";Provider=SQLNCLI;Auto Translate=false;";
//Added spaces to retain password!!!
sourceCon = sourceCon.Replace(";", "; ");
connectionManager.ConnectionString = sourceCon;
Debug.WriteLine(connectionManager.ConnectionString.ToString());
break;
case "DestinationConnection":
builder = new SqlConnectionStringBuilder(sourceConnection) { PersistSecurityInfo = true };
builder.Remove("Initial Catalog");
builder.Add("Initial Catalog", "StagingArea");
var destCon = builder.ConnectionString + ";Provider=SQLNCLI;Auto Translate=false;";
//Added spaces to retain password!!!
destCon = destCon.Replace(";", "; ");
connectionManager.ConnectionString = destCon;
Debug.WriteLine(connectionManager.ConnectionString.ToString());
break;
}
}
pkgResults = pkg.Execute();
}
catch (Exception e)
{
throw;
}
Console.WriteLine(pkgResults.ToString());
}
I played about with the ConnectionStrings and noticed after a while that the original String had spaces between each property.
Running 2 tests I found that without spaces the Password was lost...
connectionManager.ConnectionString = destCon;
Test 1: No Spaces:
When destCon = Data Source=xxx.xxx.xxx.xxx;Initial Catalog=StagingArea;User ID=*****;Password=*****;Provider=SQLNCLI;Auto Translate=false;
Then connectionManager.ConnectionString = Data Source=xxx.xxx.xxx.xxx;User ID=*****;Initial Catalog=StagingArea;Provider=SQLNCLI;Auto Translate=false;
Test 2: Spaces:
When destCon = Data Source=xxx.xxx.xxx.xxx; Initial Catalog=StagingArea; User ID=*****; Password=*****; Provider=SQLNCLI; Auto Translate=false;
Then connectionManager.ConnectionString = Data Source=xxx.xxx.xxx.xxx; Initial Catalog=StagingArea; User ID=*****; Password=*****; Provider=SQLNCLI; Auto Translate=false;
No idea why this happens, but without spaces the ordering is adjusted and the Password field is lost.

Get Connection String Without Password Value in C#

I try create method for get the connection string value but without value for password, or show password like * character. I need used it in logging.
I use ConnectionStringBuilder for Oracle, SqlServer.
Anyway, another way -better- to implement it ? Maybe more generic . And what it happens it ProviderName is empty...
public static string GetConnectionStringWithouPassword(this ConnectionStringSettings cs)
{
if (cs == null || string.IsNullOrEmpty(cs.ConnectionString)) return null;
if (cs.ProviderName.ToLower().Equals("Oracle.DataAccess.Client".ToLower()))
{
var builderOra = new Oracle.DataAccess.Client.OracleConnectionStringBuilder(cs.ConnectionString);
return "";
}
if (cs.ProviderName.ToLower().Equals("System.Data.SqlClient".ToLower()))
{
var builderSql = new SqlConnectionStringBuilder(cs.ConnectionString);
return "";
}
return null;
}
//
public static string ObtenerCadenasConexion()
{
var sb = new StringBuilder();
ConnectionStringSettingsCollection settings = ConfigurationManager.ConnectionStrings;
if (settings != null)
{
foreach (ConnectionStringSettings cs in settings)
{
sb.AppendLine("Name: " + cs.Name);
sb.AppendLine("ProviderName: " + cs.ProviderName);
sb.AppendLine("ConnectionString: " + cs.GetConnectionStringWithouPassword() + Environment.NewLine);
}
}
return sb.ToString();
}
check this one: DbConnectionStringBuilder Class
you can use the Remove method, no magic parsing required:
for example, from that MSDN page:
static void Main()
{
DbConnectionStringBuilder builder = new
DbConnectionStringBuilder();
builder.ConnectionString =
#"Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\Demo.mdb;" +
"Jet OLEDB:System Database=system.mdw;";
// Try to remove an existing item.
TryRemove(builder, "Provider");
// Try to remove a nonexistent item.
TryRemove(builder, "User ID");
// Try to remove an existing item,
// demonstrating that the search isn't
// case sensitive.
TryRemove(builder, "DATA SOURCE");
Console.ReadLine();
}
static void TryRemove(DbConnectionStringBuilder builder, string itemToRemove)
{
if (builder.Remove(itemToRemove))
{
Console.WriteLine(#"Removed '{0}'", itemToRemove);
}
else
{
Console.WriteLine(#"Unable to remove '{0}'", itemToRemove);
}
Console.WriteLine(builder.ConnectionString);
}
Check the Connection.PersistSecurityInfo property, you may drop this information as soon as the connection is created automatically.

Categories