I have a problem, so I thought I would come to the brightest minds on the web.
I have written an ASP.NET MVC application that interfaces with a web service provided by another application. My app basically just adds some features to the other web application.
Both applications have a database. I am trying to limit the configuration for my application by using the other applications SQL Server credentials. This is so that if they decide to change the password for the other application, mine will just start working.
These credentials are saved in a .DSN file that my application can reach. How can I get my application, which uses Entity Framework, to use a connection string that is created from the details read in the .DSN file?
I can figure out the code to read the .DSN file, so if you wish to provide some code examples you can base them around setting the connection string for EF.
I am also open to other solutions, or even reasons why I shouldn't do this.
Thanks in advance.
PS. As I was writing this, I came up with a little concept. I am going to test it out now to see how it goes. But here is the basics:
On start up, read the needed details into static properties.
public MyContext() : base(getConnectionString()) { }
3.
private SomeObjectTypeHere getConnectionString()
{
//read static properties
//return .....something..... not sure yet....
}
Thoughts on that maybe?
EDIT
I have created a method that reads the .DSN file and gets the server, the user id and the password. I now have these stored in static properties. In my context, how can I set my connection string now that i have the required details.
So, the biggest issue that I was really having was how to set my connection string in Entity Framework. But I was also hoping that maybe someone else had worked with .DSN files.
Anyway, here was my solution. Still looking for problems that might arise from this, so if you can see any issues, let me know!
First, I created a method that was run on startup. This method ran through the .DSN file and picked out the gems.
Keep in mind that I have never worked with .DSN files, and the section that gets the password is unique to my situation.
var DSNFileContents = File.ReadAllLines(WebConfigurationManager.AppSettings["AppPath"] + #"\App.DSN");//reads DSN into a string array
//get UID
string uid = DSNFileContents.Where(line => line.StartsWith("UID")).First().Substring(4);//get UID from array
//test if uid has quotes around it
if (uid[0] == '"' && uid[uid.Length - 1] == '"')
{
//if to starts with a quote AND ends with a quote, remove the quotes at both ends
uid = uid.Substring(1, uid.Length - 2);
}
//get server
string server = DSNFileContents.Where(line => line.StartsWith("SERVER")).First().Substring(7);//get the server from the array
//test if server has quotes around it
if (server[0] == '"' && server[server.Length - 1] == '"')
{
//if to starts with a quote AND ends with a quote, remove the quotes at both ends
server = server.Substring(1, server.Length - 2);
}
//THIS WON'T WORK 100% FOR ANYONE ELSE. WILL NEED TO BE ADAPTED
//test if PWD is encoded
string password = "";
if (DSNFileContents.Where(line => line.StartsWith("PWD")).First().StartsWith("PWD=/Crypto:"))
{
string secretkey = "<secret>";
string IV = "<alsoSecret>";
byte[] encoded = Convert.FromBase64String(DSNFileContents.Where(line => line.StartsWith("PWD")).First().Substring(12));
//THIS LINE IN PARTICULAR WILL NOT WORK AS DecodeSQLPassword is a private method I wrote to break the other applications encryption
password = DecodeSQLPassword(encoded, secretkey, IV);
}
else
{
//password was not encrypted
password = DSNFileContents.Where(line => line.StartsWith("PWD")).First().Substring(4);
}
//build connection string
SqlConnectionStringBuilder cString = new SqlConnectionStringBuilder();
cString.UserID = uid;
cString.Password = password;
cString.InitialCatalog = "mydatabase";
cString.DataSource = server;
cString.ConnectTimeout = 30;
//statProps is a static class that I have created to hold some variables that are used globally so that I don't have to I/O too much.
statProps.ConnectionString = cString.ConnectionString;
Now that I have the connection string saved, I just have my database Context use it as below,
public class myContext : DbContext
{
public myContext() : base(statProps.ConnectionString) { }
//all my DbSets e.g.
public DbSet<Person> Persons{ get; set; }
}
This is simple, yes, but I hoping that it can provide some information to anyone that was looking to do something similar but was not sure about how it should be handled.
Again, let me know if you like or dislike this solution and if you dislike it, what is your solution and why.
Thanks again!
Related
I have developed an accounting program that is working beautifully, but now a new need has arisen.
When I enter the program, by default it reads the DB that I put in the file WinSCM.exe.config and if I want to change I have to exit the program and edit the file changing the DB name.
I did not want it to be this way, because my client does accounting for several companies and each company is a DB, so I wanted a way to select a company and when selecting this company the database is automatically changed in the release version.
I'm using Entity Framework to connect to Sql Server DB
Can someone help me?
I'm not sure what reading your DB is, but normally when you use Entity Framework you create a DbContext object whenever you need to do a query, or at utmost a few queries. You are not supposed to keep this DbContext alive for longer periods of time, say more than a few seconds. A minute would be very rare.
Whenever you create the Dbcontext instance you could use the default constructor that uses the config file to get the connection string to the database.
However one of the other constructors let you define the connection string to the database in the constructor. So if you want to construct your DbContext and connect it to a different database, just use that constructor
If you don't know the connection string, but you have a DbConnection to the database, there will be even a constructor for this case.
Hi Everybody Thank alot for your Answer. I just Solved My Question like this:
Fisrt of all, I created a class wich I called ConnetionTolls with this Content://.
public static class ConnectionTools
{
// all params are optional
public static void ChangeDatabase(
this DbContext source,
string initialCatalog = "",
string dataSource = "",
string userId = "",
string password = "",
bool integratedSecuity = true,
string configConnectionStringName = "")
/* this would be used if the
* connectionString name varied from
* the base EF class name */
{
try
{
// use the const name if it's not null, otherwise
// using the convention of connection string = EF contextname
// grab the type name and we're done
var configNameEf = string.IsNullOrEmpty(configConnectionStringName)
? source.GetType().Name
: configConnectionStringName;
// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
(System.Configuration.ConfigurationManager
.ConnectionStrings[configNameEf].ConnectionString);
// init the sqlbuilder with the full EF connectionstring cargo
var sqlCnxStringBuilder = new SqlConnectionStringBuilder
(entityCnxStringBuilder.ProviderConnectionString);
// only populate parameters with values if added
if (!string.IsNullOrEmpty(initialCatalog))
sqlCnxStringBuilder.InitialCatalog = initialCatalog;
if (!string.IsNullOrEmpty(dataSource))
sqlCnxStringBuilder.DataSource = dataSource;
if (!string.IsNullOrEmpty(userId))
sqlCnxStringBuilder.UserID = userId;
if (!string.IsNullOrEmpty(password))
sqlCnxStringBuilder.Password = password;
// set the integrated security status
sqlCnxStringBuilder.IntegratedSecurity = integratedSecuity;
// now flip the properties that were changed
source.Database.Connection.ConnectionString
= sqlCnxStringBuilder.ConnectionString;
}
catch (Exception ex)
{
// set log item if required
}
}
********the way to use it is like this***************
//I use this method in a diferent Class
//This method returns the Entity i use with new connections
public static MyEntities SelectDb(String DataBase,String sqlUser,String pw, String serverInstance){
var selectedDbase = new MyEntities();
// so only reference the changed properties
// using the object parameters by name
selectedDbase.ChangeDatabase
(
initialCatalog: DataBase,
userId: sqlUser,
password: pw,
dataSource: serverInstance// could be ip address 100.23.45.67 etc
);
return selectedDbase;
}
I want to thank everyone here and on other forums because this was the result of Your Contributions
I'm trying to make C# program that gets a line on a website and use it.
Unfortunately, I don't know the full line on the site. I only know "steam://joinlobby/730/". Although, what comes after "/730/" is always different.
So i need help getting the full line that comes after it.
What I've got:
public void Main()
{
WebClient web = new WebClient();
// here is the site that i want to download and read text from it.
string result = web.DownloadString("http://steamcommunity.com/id/peppahtank");
if (result.Contains("steam://joinlobby/730/"))
{
//get the part after /730/
}
}
I can tell you that it always ends with "xxxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxxx"
so: steam://joinlobby/730/xxxxxxxxx/xxxxxxxx.
What's to prevent you from just splitting the string on '/730/'?
result.Split(#"/730/")[1]
https://msdn.microsoft.com/en-us/library/system.string.split(v=vs.110).aspx
The easiest method for this particular case would be to take the first part, and then just skip that many characters
const string Prefix = #"steam://joinlobby/730/";
//...
if(result.StartsWith(Prefix))
{
var otherPart = result.SubString(Prefix.Length);
// TODO: Process other part
}
Make sure your result is not null and begins with steam://joinlobby/730/
if(string.IsNullOrWhiteSpaces(result) && result.StartsWith("steam://joinlobby/730/"))
{
string rest = result.SubString(("steam://joinlobby/730/").Length);
}
I've an application which insert/save data in different databases hosted on different server. UI may be different but at the end data which is getting saved is almost same.
So i want to use the same DataAccessLayer but want to change the connectionString based on the loggedin user.
Dependency can be configured in startup.cs but at that time i may not know the DataBase user would like to work with.
on login page i'm asking user to select the database to work with, so only way to change the connection string is after login page.
Any suggestion?
public class ConnectionRepository : IConnectionRepository
{
private IDbConnection _cnn = null;
public IDbConnection GetOpenConnection(string databaseName)
{
if (_cnn != null && _cnn.ConnectionString.ToLower().Contains(databaseName.ToLower()))
{
_cnn.Open();
return _cnn;
}
var cnn = ConfigurationManager.ConnectionStrings["DefaultConnection"].ToString();
//Now replace database name in connection string with whichever one supplied
var cb = new SqlConnectionStringBuilder(cnn) { InitialCatalog = databaseName };
// wrap the connection with a profiling connection that tracks timings
return new ProfiledDbConnection(new SqlConnection(cb.ConnectionString), MiniProfiler.Current);
}
}
This code replaces the InitialCatalog (database name) part of the connection string dynamically base on the supplied name. The current name is stored in session when the user logs in.
Hope this helps.
Ok. So this question might be a bit stupid but as I've searched and searched and haven't found a working solution I thought I might ask here.
I've put up a simple PHP page that gets 2 parameters from the url myusername and mypassword. Then gets 3 int values from a database according to the username and password given.
(tested it By typing the url in with the parameters and the PHP script itself works. Even made it to echo the 3 integers on the page to make sure)
Now to the problematic part. I'm using Visual Studio 2013 and making an Universal App for Windows 8.1. And I just can't seem to get the httpClient to get me any data from there. Through browsing the forums I haven't been able to find anything that works. Couldn't have tested all either as most use GetResponse() which doesn't work in VS 2013. As I'm fairly new to the C# coding it could be as simple as to a little mistake in the dozens of tests I've done.
Made a login screen with 2 text fields. And I can build the url in form of "www.something.com/something/somephp?myusername=UserNameGiven&mypassword=PasswordGiven"
If anyone could give a simple solution on how I might be able to get the results from the page that address opens (only shows the 3 integers through echo... can remove those too if those arent required for the C# code to work. String format would probably be ideal if not too much to ask...
Ok made a new GetScores async method for the code you gave SnyderCoder. Throwing that Task on login button would have required coding beyond my knowhow for the moment atleast.
Still Results.Text field remains at the default status and shows no change.
Changed the LoginButton back to async without task.
the state of my code from the c# is atm is
private async void LoginButton_Click(object sender, RoutedEventArgs e)
{
string UserName, Password;
UserName = UserNameFeedField.Text.ToString();
Password = PasswordFeedField.Text.ToString();
string url = "something.com/something/GetScores.php?myusername=" + UserName + "&mypassword=" + Password;
URL.Text = url;
// GetScores(url);
using (Windows.Web.Http.HttpClient client = new Windows.Web.Http.HttpClient())
{
string contentOFPage = await client.GetStringAsync(new Uri(url));
Results.Text = contentOFPage;
}
}
incase it matters here is the PHP code portion
<?php
$host="db_host"; // Host name
$username="db_user"; // Mysql username
$password="db_pswd"; // Mysql password
$db_name="db_name"; // Database name
$tbl_name="db_table"; // Table name
// Connect to server and select databse.
mysql_connect("$host", "$username", "$password")or die("cannot connect");
mysql_select_db("$db_name")or die("cannot select DB");
// username and password sent from form
$myusername=$_GET["myusername"];
$mypassword=$_GET["mypassword"];
// To protect MySQL injection (more detail about MySQL injection )
$myusername = stripslashes($myusername);
$mypassword = stripslashes($mypassword);
$myusername = mysql_real_escape_string($myusername);
$mypassword = mysql_real_escape_string($mypassword);
$sql="SELECT field1 as LowB, field2 as LongB, field3 as Bs FROM $tbl_name WHERE UserID='$myusername' and UserPSWD='$mypassword'";
$result=mysql_query($sql);
// this part only shows the variables gotten from the query and echoes those on the page
// was only made to test that the PHP works.
while ($row = mysql_fetch_assoc($result)) {
echo ($row["LowB"] . " " . $row["LongB"] . " " . $row["Bs"]);
}
?>
First a async method always needs to return a task. For the rest:
private async void LoginButton_Click(object sender, RoutedEventArgs e)
{
string UserName = UserNameFeedField.Text.ToString();
string Password = PasswordFeedField.Text.ToString();
string url = "www.something.com/something/some.php?myusername=" + UserName + "&mypassword=" + Password;
using (Windows.Web.Http.HttpClient client = new Windows.Web.Http.HttpClient())
{
string contentOfPage = await client.GetStringAsync(new Uri(url));
//Do something with the contentOfPage
}
}
I have an EF5 ASP.NET MVC 3 (Razor) web site, running under IIS7. Now I want to be able to change the connection string to the MSSQL database depending on the subdomain of the URL, e.g. foo.mydomain.com should connect to my "Foo" database, and bar.mydomain.com should connect to the "Bar" database.
Obviously the DNS records are set up so that they all point to the same web site.
What's the most efficient way of achieving this?
why don't you start passing your own SqlConnection to your YourDbContext?
var partialConString = ConfigurationManager.ConnectionStrings["DBConnectionStringName"].ConnectionString;
var connection = new SqlConnection("Initial Catalog=" + Request.Url.Host + ";" + partialConString);
var context = new MyDbContext(connection, true);
You can also change database in the DBContext:
context.Database.Connection.ChangeDatabase("newDbname");
It's not very easy...
You should change the constructor of object context to dynamically change the connection string.
Take the subdomain name using System.Web.HttpContext.Current.Request.Url.Host. Then use it to compute the proper connection string.
You should do this in the designer generated code. Of course this is not a good place.. to make it work use the T4 templating. Open your model and right click on the blank designer surface, then select "Add code generation item" -> Ado.net entity object generation. This will create a .tt file. Open it and look for the constructor syntax. Add your logic there.
Good luck!
I've come up with what I feel is a better solution than all those proposed to date. I'm using the default EntityModelCodeGenerator, so perhaps there are other, better, solutions for other templates - but this works for me:
Create the other half of the partial class MyEntities.
Override OnContextCreated(), which is called from within the class constructor.
Change the store connection string using a regex.
This comes out as follows:
partial void OnContextCreated()
{
// change connection string, depending on subdomain
if (HttpContext.Current == null) return;
var host = HttpContext.Current.Request.Url.Host;
var subdomain = host.Split('.')[0];
switch (subdomain)
{
case "foo":
ChangeDB("Foo");
break;
case "bar":
ChangeDB("Bar");
break;
}
}
private void ChangeDB(string dbName)
{
var ec = Connection as EntityConnection;
if (ec == null) return;
var match = Regex.Match(ec.StoreConnection.ConnectionString, #"Initial Catalog\s*=.*?;", RegexOptions.IgnoreCase);
if (!match.Success) return;
var newDbString = "initial catalog={0};".Fmt(dbName);
ec.StoreConnection.ConnectionString = ec.StoreConnection.ConnectionString.Replace(match.Value, newDbString);
}
Either use different connection strings in the web.config. Maybe research a bit if you can have conditional XSL transformations, that way, when you publish on a specific configuration the web.Release.config will change your Web.Config to be what you need it to be.
Or, use |DataDirectory| string substitution - http://msdn.microsoft.com/en-us/library/cc716756.aspx
more on DataDirectory string substitution here:
http://forums.asp.net/t/1835930.aspx/1?Problem+With+Database+Connection
I guess, if you want to be by the book, create build configurations for each of your separate releases and put the connection string in the respective web..config and when you publish, that XSL transformation will put the connection string in the resulting web.config and voila.
I've done something like that recently by adding some custom configuration, which uses the host header to determine the connectionStringName, which has to be used.
EF5 has a constructor, which can handle this name
var context = new MyDbContex("name=<DBConnectionStringName>");
I just did for a project
public partial class admpDBcontext : DbContext
{
public static string name
{
get
{
if (System.Web.HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority).ToString() == "http://fcoutl.vogmtl.com")
{
return "name=admpDBcontext";
}
else { return "name=admpNyDBcontext"; }
}
}
public admpDBcontext()
: base(name)
{
}
}
And in the web.config I add the connectionString.