Adding a second SQL data provider to ScrewTurn - c#

I need to add a second sql data provider to our screwturn wiki, i added the connection the web config but can't seem to add it to the startup. I have...
public static string GetSettingsStorageProviderConfiguration2()
{
string config = WebConfigurationManager.AppSettings["SettingsStorageProviderConfig2"];
if (config != null) return config;
else return "";
}
Then in startup I have duplicated the host and settings provider info, this is probably redundant but i'm not sure how to do it otherwise...
Host Host2 = new Host();
ISettingsStorageProviderV30 ssp2 = ProviderLoader.LoadSettingsStorageProvider(WebConfigurationManager.AppSettings["SettingsStorageProvider2"]);
ssp2.Init(Host2, GetSettingsStorageProviderConfiguration2());
Collectors.SettingsProvider2 = ssp2;
I updated TryLogin with
IUsersStorageProviderV30 connection2 = Collectors.UsersProviderCollector.GetProvider(StartupTools.GetSettingsStorageProviderConfiguration()) as IUsersStorageProviderV30;
//IUsersStorageProviderV30[] providers2 =
// Then try all other providers
List<IUsersStorageProviderV30> providers = Collectors.UsersProviderCollector.AllProviders.OfType<IUsersStorageProviderV30>().ToList();
providers.Add(connection2);
But I'm missing something to make connection2 not return null.
Am I way out in left field here? Is there a easier way to go about this?

Related

How to add a field in my quartz configuration dynamically?

I have a quartz configuration section in my web.config, and I want to add a key value field to it. (I know I can just go to the web.config and add it manually but that defeats the purpose)
I tried using this way
var config = (NameValueCollection)WebConfigurationManager.GetSection("quartz");
config.Add("quartz.dataSource.quartzDS.connectionString", "data source =..");
but it failed because collection is read only and can't be modified. Any tip to how to do this?
Edit: I ended up copying the config to a nameValueCollection and then copying it to another one (for the readonly properties) add the key values I want and passing it to the function I needed.
var oldConfig = (NameValueCollection)WebConfigurationManager.GetSection("quartz");
var config = Test(oldConfig);
var connectionString = unitOfWork.GetConnectionStringByTenantIdentifier(tenantId);
config.Add("quartz.dataSource.quartzDS.connectionString", connectionString);
await unitOfWork.GetService<SchedulerService>().StartScheduler(config, tenantId);
this way I will have the custom configuration for every tenant the way I want it. Sorry if my question wasn't clear.
You can actually do this in two ways.
One way is to set your dynamic connection string in the standard AppSettings section and then create a new Quartz Scheduler with a new set of XML properties (an example is provided in Quartz.NET distribution, so I will cut this short)
var properties = new NameValueCollection
{
["quartz.scheduler.instanceName"] = "XmlConfiguredInstance",
["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz",
... etc.
};
ISchedulerFactory sf = new StdSchedulerFactory(properties);
IScheduler sched = await sf.GetScheduler();
Then you can save your non-const string in the AppSettings and get it form there.
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.AppSettings.Settings.Add("quartz.dataSource.quartzDS.connectionString", connstring);
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
Or you can read your whole settings file as XML, as previously answered, BUT you have to make sure that any edits are done before you initialize the default Quartz Scheduler, as it's properties become read-only, and to change them you will have to create a new ISchedulerFactory anyway, which kinda beats the purpose.
var xmlDoc = new XmlDocument();
xmlDoc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
xmlDoc.SelectSingleNode("//quartz/add[#key='quartz.dataSource.quartzDS.connectionString']").Attributes["value"].Value = "...";
xmlDoc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
ConfigurationManager.RefreshSection("quartz");
But I advise you not to edit your main config file at runtime at all, and instead use an ISchedulerFactory XmlConfiguredInstance while getting and saving the connstring into a UAC-compatible location in any format you like (to prevent Modifying app.config at runtime throws exception from happening)
Still if you want to use the config file you can use this tutorial from Yi Zeng for further reading
You can try using XmlDocument classes to go to a lower level.
Make sure the user of your app has write permissions to the config file
public static void WriteKey(String configFileName, String key, String value)
{
XmlDocument doc = new XmlDocument();
doc.Load(configFileName);
XmlNode node = doc.SelectSingleNode("//quartz");
if (node == null)
{
throw new InvalidOperationException("quartz section not found in config file.");
}
try
{
XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[#key='{0}']", key));
if ((elem != null))
{
elem.SetAttribute("value", value);
}
else
{
elem = doc.CreateElement("add");
elem.SetAttribute("key", key);
elem.SetAttribute("value", value);
node.AppendChild(elem);
}
doc.Save(configFileName);
}
catch
{
throw new InvalidOperationException("Error writing config file");
}
}

Entity set connection timeout

How can I set the value of connectionTimeout (not commandTimeout) of context by coding (not in connection string) ?
This is readonly:
DbContext.Database.Connection.ConnectionTimeout = 10;
Thanks
Udpate:
My probleme is to test if my context is available quickly and the default time is to long ?
I tried this :
int? oldTimeOut = RepositoryDbContext.Database.CommandTimeout;
try
{
RepositoryDbContext.Database.Connection.ConnectionTimeout = 10; //readonly
RepositoryDbContext.Database.CommandTimeout = 10; // doesn't work, the value stay the same
RepositoryDbContext.Database.Connection.Open();
RepositoryDbContext.Database.Connection.Close();
return true;
}
catch
{
return false;
}
finally
{
RepositoryDbContext.Database.CommandTimeout = oldTimeOut;
}
But I can't change the connectionTimeout is readOnly and the commandTimeout doesn't set the value...
I'm not aware of any option to change the connection timeout via the EF API. You can however change the connection string at runtime. You could parse the configured connection string and change the timeout parameter, or add one if it does not exist.
If you are working with SQL Server only, I would suggest using SqlConnectionStringBuilder. Use the constructor that takes an existing connection string, change the ConnectTimeout, get the modified connection string, and use that connection string when constructing your DbContext.
Depending on what you are actually trying to solve, one alternative might be to use SlowCheetah to easily generate the web.config, with different configuration strings, for different build types.
http://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5
UPDATE
Based on your comment...
Try something like
string normalConnectionString = RepositoryDbContext.Database.Connection.ConnectionString;
var connectionBuilder = new SqlConnectionStringBuilder(normalConnectionString);
connectionBuilder.ConnectTimeout = 10;
string testConnectionString = connectionBuilder.ConnectionString;
using (var testRepositoryDbContext = new RepositoryDbContextType(testConnectionString))
{
try
{
testRepositoryDbContext.Database.Connection.Open();
testRepositoryDbContext.Database.Connection.Close();
return true;
}
catch
{
return false;
}
}

HOW TO: dynamic connection string for entity framework

Like the title. How can I do it?
I tried something, but it doesn't work like I was expecting.
I'm using an Entity Framework model. I need to pass my connection string like parameter, so, in another file, I've written
namespace MyNamespace.Model
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class MyEntities: DbContext
{
public MyEntities(string nameOrConnectionString) : base(nameOrConnectionString)
{
}
}
}
When I startup the app, I call this constructor in this way, so I can refer to this from anyway in the app:
public static MyEntities dbContext = new MyEntities(mdlImpostazioni.SetConnectionString());
where mdlImpostazioni.SetConnectionString() returns a string (the data are correct):
server=192.168.1.100\SVILUPPO;database=MyDB;uid=myName;pwd=111111;
When I execute this code, it seems to be all ok, but when I try to make a query like:
var query = (from r in MainWindow.dbContext.TabTipoSistema select r);
it throws an exception from here:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException(); //exception here
}
So, this is a bad way... which is the right one? (using only code C#, not from xaml)
Your approach is correct, but you need to remember the connection string for EF requires the metadata and so on. So use the EntityConnectionStringBuilder. For example:
// the model name in the app.config connection string (any model name - Model1?)
private static string GetConnectionString(string model, YourSettings settings)
{
// Build the provider connection string with configurable settings
var providerSB = new SqlConnectionStringBuilder
{
// You can also pass the sql connection string as a parameter instead of settings
InitialCatalog = settings.InitialCatalog,
DataSource = settings.DataSource,
UserID = settings.User,
Password = settings.Password
};
var efConnection = new EntityConnectionStringBuilder();
// or the config file based connection without provider connection string
// var efConnection = new EntityConnectionStringBuilder(#"metadata=res://*/model1.csdl|res://*/model1.ssdl|res://*/model1.msl;provider=System.Data.SqlClient;");
efConnection.Provider = "System.Data.SqlClient";
efConnection.ProviderConnectionString = providerSB.ConnectionString;
// based on whether you choose to supply the app.config connection string to the constructor
efConnection.Metadata = string.Format("res://*/Model.{0}.csdl|res://*/Model.{0}.ssdl|res://*/Model.{0}.msl", model); ;
return efConnection.ToString();
}
// Or just pass the connection string
private static string GetConnectionString(string model, string providerConnectionString)
{
var efConnection = new EntityConnectionStringBuilder();
// or the config file based connection without provider connection string
// var efConnection = new EntityConnectionStringBuilder(#"metadata=res://*/model1.csdl|res://*/model1.ssdl|res://*/model1.msl;provider=System.Data.SqlClient;");
efConnection.Provider = "System.Data.SqlClient";
efConnection.ProviderConnectionString = providerConnectionString;
// based on whether you choose to supply the app.config connection string to the constructor
efConnection.Metadata = string.Format("res://*/Model.{0}.csdl|res://*/Model.{0}.ssdl|res://*/Model.{0}.msl", model);
// Make sure the "res://*/..." matches what's already in your config file.
return efConnection.ToString();
}
EDIT
The exception you get is because when you pass a pure SQL connection string, it assumes you are working with Code first, so it calls the OnModelCreation event. When you include the MetaData section as shown above, that tells EF it's a complete EF connection string.
I believe the problem lies on the Datasource you specify. You need to add the port of the connection, e.g if your SQL Server is configured on Port 1433, try:
server=192.168.1.100,1433\SVILUPPO;database=MyDB;uid=myName;pwd=111111;
more details about connection strings you can find Here
Also I am not sure if uid and pwd are valid, better try User ID and Password:
Server=192.168.1.100,1433\SVILUPPO;Database=MyDB;User ID=myName;Password=111111;
Finally mind the case sensitivity.

Can entity framework be used with a connection string given at runtime? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I've got an application that's an extension for another application. The primary application has a context which provides a connection string. In the past, I've setup entity framework and the first step is to set to connection string.
In this case, I can't set the connection string because I don't have it until runtime. Can I still use Entity Framework? If so, how do I set it up?
Absolutely:
SqlConnection dbConn = new SqlConnection("your_connection_string");
EntityConnection entityConnection = new EntityConnection(dbConn);
var yourEdmx = new DbModel(entityConnection);
Use EntityConnectionStringBuilder Class.
EntityConnectionStringBuilder entityBuilder =
new EntityConnectionStringBuilder();
entityBuilder.Provider = providerName;
entityBuilder.ProviderConnectionString = providerString;
Yes, you can specify a connection when creating the Context.
You can also set the context database default connection factory after the fact:
dbContext.Database.DefaultConnectionFactory = someConnectionString;
Simple method:
var DB = new Your_Entities();
DB.Database.Connection.ConnectionString = "Your_Connection_String";
I had this problem with a project... everything is fine, all wonders... When you run the application in you computer, how do you adapt the database connection to the different users?
I did everything here and other many post similar to this, and nothing seams to work... Yes, the code works, the data context catch the new info for the connection, but it simply DON'T WORK... :'(
I found a lifesaver example that solve my problems, it's a bunch of code but, DBCon has the information of the new connection:
Encripter enc = new Encripter();
string strconfig = u.readFile(u.ubicacionActual() + "\\conn.config");
DBCon dbcon = JsonConvert.DeserializeObject<DBCon>(enc.decrypt(strconfig));
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
EntityConnectionStringBuilder efb = new EntityConnectionStringBuilder(config.ConnectionStrings.ConnectionStrings["ProyectEntities"].ConnectionString);
SqlConnectionStringBuilder sqb = new SqlConnectionStringBuilder(efb.ProviderConnectionString);
// Now we can set the datasource
sqb.DataSource = dbcon.datasource;
sqb.InitialCatalog = dbcon.catalog;
sqb.UserID = dbcon.user;
sqb.Password = dbcon.password;
efb.ProviderConnectionString = sqb.ConnectionString;
// to rewrite the app.config!
ChangeEFConnectionString("ProyectEntities", efb.ProviderConnectionString);
ProyectEntities db = new ProyectEntities(); // dbcontext
The magic function (Well it's not really magic! Just overwrite the app.config)
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 through 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);
//
entityBuilder.ProviderConnectionString = newValue;
//back the modified connection string to the configuration file
atr.NextAttribute.Value = entityBuilder.ToString();
}
}
}
}
doc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
All credits to a Bahrudin Hrnjica

How to in-code supply the password to a connection string in an ADO.Net Entity Data Model

I've been following this tutorial on how to create an OData service.
http://www.hanselman.com/blog/CreatingAnODataAPIForStackOverflowIncludingXMLAndJSONIn30Minutes.aspx
And it works flawlessly ... but, in the Entity Data Model Wizard, when it asks you to "Choose Your Data Connection" it gives you this warning.
"This connection string appears to contain sensitive data (for example, a password) that is required to connect to the database. Storing sensitive data in the connection string can be a security risk. Do you want to include this sensitive data in the connection string?"
If I choose: "No, exclude sensitive data from the connection string. I will set it in my application code."
I do not see where I can, "in my application code" insert the password. (My company stores them encrypted in the registry)
Plus, I have multiple DBs that I need to connect to, depending on the environment (Dev, CA, or Prod) and I need to know what DB is referenced in the connection string to get the correct password.
Thanks.
When you create your context, you can set a connection string. To build this connection string, you can parse the connection string without the password with an EntityConnectionStringBuilder and then parse the inner connection string with an other ConnectionStringBuilder, depending on your browser. Then you can set the password and pass it to the constructor.
var originalConnectionString = ConfigurationManager.ConnectionStrings["your_connection_string"].ConnectionString;
var entityBuilder = new EntityConnectionStringBuilder(originalConnectionString);
var factory = DbProviderFactories.GetFactory(entityBuilder.Provider);
var providerBuilder = factory.CreateConnectionStringBuilder();
providerBuilder.ConnectionString = entityBuilder.ProviderConnectionString;
providerBuilder.Add("Password", "Password123");
entityBuilder.ProviderConnectionString = providerBuilder.ToString();
using (var context = new YourContext(entityBuilder.ToString()))
{
// TODO
}
I added a "dummy" password in the configuration file ("XXXXX"), then replaced that value with the real password in the entity constructor
public MyDatabaseContainer() : base("name=MyDatabaseContainer")
{
Database.Connection.ConnectionString = Database.Connection.ConnectionString.Replace("XXXXX","realpwd");
}
Modify the constructor of the entities
public sampleDBEntities() : base("name=sampleDBEntities")
{
this.Database.Connection.ConnectionString = #"Data Source=.\;Initial Catalog=sampleDB;Persist Security Info=True;User ID=sa;Password=Password123"; ;
}
My sample application was written in "Database First" mode and the "CreateNewConnectionString" method below works just fine (though it doesn't look all that elegant.)
The "CreateNewConnectionString2" method looks really elegant, BUT causes an exception telling me it's only valid in "Code First" mode.
So I'm providing both methods along with the constructor I modified to use my methods. NOTE AND BEWARE, I've modified code generated by a template and that is subject to being overwritten if the code is regenerated. To me it seems like the right place to put it.
If your application was generated in "Code First" mode, you may need to use "CreateNewConnectionString2" (I have not yet tested this option.)
I hasten to admit that I copied both code blocs from other postings as I don't yet know nearly enough about all this to write my own code.
private static string CreateNewConnectionString(string connectionName, string password)
{
var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~").ConnectionStrings.ConnectionStrings[connectionName];
//or:
//var config = ConfigurationManager.ConnectionStrings[connectionName];
var split = config.ConnectionString.Split(Convert.ToChar(";"));
var sb = new System.Text.StringBuilder();
for (var i = 0; i <= (split.Length - 1); i++)
{
if (split[i].ToLower().Contains("user id"))
{
split[i] += ";Password=" + password;
}
if (i < (split.Length - 1))
{
sb.AppendFormat("{0};", split[i]);
}
else
{
sb.Append(split[i]);
}
}
return sb.ToString();
}
private static string CreateNewConnectionString2(string connectionName, string password)
{
var originalConnectionString = ConfigurationManager.ConnectionStrings[connectionName].ConnectionString;
var entityBuilder = new EntityConnectionStringBuilder(originalConnectionString);
var factory = DbProviderFactories.GetFactory(entityBuilder.Provider);
var providerBuilder = factory.CreateConnectionStringBuilder();
providerBuilder.ConnectionString = entityBuilder.ProviderConnectionString;
providerBuilder.Add("Password", password);
entityBuilder.ProviderConnectionString = providerBuilder.ToString();
return entityBuilder.ProviderConnectionString;
}
public ChineseStudyEntities()
: base(CreateNewConnectionString("ChineseStudyEntities", "put YOUR password here")) // base("name=ChineseStudyEntities")
{
}

Categories

Resources