If i have a dll which i use in many web applications to use methods in this dll in my applications.
What 's the best practice to handle the connection string ?
The dll methods are static methods ..
this is what i do
private static String connectionString = "User Id=xxx;Password=xxx;Host=xxx;Server=xxx;Service=1525;Database=xxx; Client Locale=ar_ae.1256; Database Locale=ar_ae.8859-6; Protocol=olsoctcp;pooling=true;Min Pool Size=4;Max Pool Size=400;Connection Timeout=30";
public static int Is_Valid_User(string p_u, string p_p)
{
int ret = 0; // invalid user
using (IfxConnection conn = new IfxConnection(connectionString))
{
IfxCommand DBCmd = new IfxCommand();
String p = My_Decryption_2(p_p);
try
{
if (conn.State == ConnectionState.Closed)
conn.Open();
DBCmd = new IfxCommand();
DBCmd.Connection = conn;
DBCmd.CommandText = "SELECT nvl(emp_num,0) FROM emp_net WHERE username = ? AND DECRYPT_CHAR(password, 'xxxxxx') = ? ";
DBCmd.Parameters.Add("user_name", p_u);
DBCmd.Parameters.Add("password", p);
using (IfxDataReader dataReader = DBCmd.ExecuteReader())
{
if (dataReader.Read())
ret = (int)dataReader[0];
dataReader.Close();
}
}
catch (ApplicationException e)
{
}
conn.Close();
}
return ret;
}
Is this a good way to use a dll in my web application ?or there 's a way better than this ?
You have pretty much shot yourself in the foot with those static methods.
Best practise is probably to refactor the class to use instance methods and inject the connection string through the constructor or properties.
Failing that you can refactor the static methods to include the connection string?
public static int Is_Valid_User(string p_u, string p_p, string connectionString)
You can hard code a reference to the [web|app]config connection string too, but that has only changed the problem (the dependency on a fixed string), not solved it.
Its better to have connection string in some sort of configuration like web.config.
Related
I am using Azure function to connect to Sql database and retrieve values. I am able to install the necessary Nuget packages and perform Sql connection and querying in the Run() function
I wish to keep this database access function alone in a separate file, and return value to the main function(Run() in this case). But when i create a new class in the Azure function project and write SQL connection code, no "using" statements can be used or installed packages can be used.
I am new to Azure functions and may be i am wrong in this approach. Can you help me out? Thanks.
.
You just need to wrap your code in a method. Here's a sample:
public class SqlQuery
{
private string cs = Environment.GetEnvironmentVariable("SqlConnectionString");
public void Query()
{
using(var conn = new SqlConnection(cs))
{
conn.Open();
var cmd = conn.CreateCommand("SELECT * FROM Table");
var dr = cmd.ExecuteReader();
if(dr == null) return;
while(dr.Read())
{
}
}
}
}
the screenshot you shared contains a class and has started implementation inside the class, whereas you should be creating at least one method inside your class and then add your code into the method which returns the data you expect.
try that it should work!
public class SqlQuery{
public void ExecuteReader()
{
private string cs =Environment.GetEnvironmentVariable("SqlConnectionString");
using(var conn = new SqlConnection(cs))
{
conn.Open();
var cmd = conn.CreateCommand("SELECT * FROM Table");
var dr = cmd.ExecuteReader();
if(dr == null) return;
while(dr.Read())
{
}
}
}}
I had small c# software that works on several database on several servers and I need to switch between different schema so..
depending on the current server ip I connect to master table on specified server
and get the schema name then add as variable within the connection string by this way ..
is it safe to use this way to make connection string flexible ?
if no then what do you suggest
string oradb = "Data Source=source;User Id=" + DBSchema + ";Password=pwd;";
In general run-time parameters are to be stored outside your code and in many cases the config file is one of the best places for that. You could use a factory method to build the connection string as in CodeProject-Don't Hard Code Your Data Providers or you could write a few lines of code to set the values using the .NET connection string builder as in ConnectionStringBuilder Class.
for example currently I have a web application that 2 web forms that need 2 different connection I will show you how I have it for 1 of the 2 forms
public static string storedProcName = "NameOfSomeStoredProc";
public string ConnString
{
get { return ConfigurationManager.ConnectionStrings["DbConn2"].ConnectionString; }
}
public string UserConnName
{
get { return string.Concat(ConfigurationManager.AppSettings["userConnName"], storedProcName); }
}
the method actual stored procedure call inside a method will look like the following I am passing in the Stored Proc name based on a static storedProcName declared above..
Create yourself a Helper Class and you can have something like the following that you would call from within your Class where you are wanting to execute the code
HelperClass.cs
public static DataSet ExecuteDataSet2(string sql, CommandType cmdType, params OracleParameter[] parameters)
{
using (DataSet ds = new DataSet())
using (OracleConnection connStr = new OracleConnection(ConfigurationManager.ConnectionStrings["DbConn2"].ConnectionString))
using (OracleCommand cmd = new OracleCommand(sql, connStr))
{
cmd.CommandType = cmdType;
cmd.CommandTimeout = 60 * 22;
foreach (var item in parameters)
{
cmd.Parameters.Add(item);
}
try
{
cmd.Connection.Open();
new OracleDataAdapter(cmd).Fill(ds);
}
catch (Exception ex)
{
utilities.SendErrorEmails(ex);
throw ex;
}
return ds;
}
}
Your Web.Config for example would look like this if you have 2 different DB connection string.. you would create the same method as above calling it ExecuteDataSet1.... and change the DbConn2 to DbConn and in the Public string ConnString change the DbConn2 to DbConn in your other class or have a check box and depending on the selection you can store botn ConnString get retrun .. calling your other one ConnString2 pretty straight forward
<connectionStrings>
<add name="DbConn" connectionString="Data Source={0};User Id={1};Password={2};" />
<add name="DbConn2" connectionString="Data Source={0};User Id={1};Password={2};" />
</connectionStrings>
<appSettings>
<add key="userConnName" value="NameOfOracleUser." />
</appSettings>
//Pay close attention to the . in the NameOfOracleUser., this depending how you have your procedures setup you would have OracleDbUserName.StoredProcedure name to execute.. notice in the Populate_DataGrin method I am passing the UserConnName and the string.Concat will pick up the storedProcName from this
public static string storedProcName = "NameOfSomeStoredProc"; works like a charm and if you had a dropdown of stored proc names to run.. it would work the same by assigning the name based on the drowpdown selection text..
last but not least the method / event that calls the ExecuteDataSet2 would look like this
private void Populate_DataGrin(int intMonth, string strLocation)
{
dtSomeDataTable = OracleDBHelper.ExecuteDataSet2(UserConnName, CommandType.StoredProcedure
, new OracleParameter("var_IntMonth", intMonth)
, new OracleParameter("var_StrLocation", strLocation)
, new OracleParameter
{
ParameterName = "p_cursor"
,
OracleDbType = OracleDbType.RefCursor
,
Direction = ParameterDirection.Output
}
).Tables[0];
YourDataGrid.DataSource = null;
YourDataGrid.DataSource = dtSomeDataTable;
YourDataGrid.DataBind();
}
I've written a function to perform MySQL statements. In this function I give in a statement and get back the MySqlDataReader, but the problem is my function do not close the connection. After a short while of using the Programm, it crashs because the new connection can't be open. This is the error i got by trying open the new connection:
error connecting: Timeout expired. The timeout period elapsed prior
to obtaining a connection from the pool. This may have occurred
because all pooled connections were in use and max pool size was
reached.
My code look like this:
MySQL Class:
class mySql
{
string cs = "server=123.123.123.123;" +
"uid=abcabc;" +
"pwd=123456;" +
"database=overflow_test;";
private MySqlConnection conn_f() // create a Connection
{
MySql.Data.MySqlClient.MySqlConnection conn;
conn = new MySql.Data.MySqlClient.MySqlConnection();
conn.ConnectionString = cs;
try
{
conn.Open();
return conn;
}
catch
{
return null;
}
}
public MySqlDataReader CMD_f(string comand) //execute SQL Command
{
MySql.Data.MySqlClient.MySqlCommand cmd;
cmd = new MySql.Data.MySqlClient.MySqlCommand();
MySqlConnection conn = conn_f();
cmd.Connection = conn;
cmd.CommandText = comand;
cmd.Prepare();
rdr = cmd.ExecuteReader();
return rdr;
}
}
and an example how i use it Main Class
class main{
mySql DB = new mySql();
public void main(){
MySqlDataReader rdr = DB.CMD_f("SELECT * FROM tbl_kategorie");
int i = 0;
while (rdr.Read())
{
string str = rdr.GetString(1);
Console.WriteLine(str);
}
}
Has someone an Idea to solve the Problem.
Sincere regards LFS96 (Fabian Harmsen)
The main problem is the inbalance in the code. The CMD_f method creates a connection, but doesn't take responsibility for it. You should rather make the method that creates the connection public, so that you can take responsibility for it in the code that can close it.
That's a bigger change, so first let's look at a smaller change to fix the code.
The data reader should expose the data connection as the Connection property. I don't see that in the documentation, so it's possible that it doesn't, but the data readers in the .NET framework does.
If the property is exposed, then you can make a quick fix to make the code work with minimal change:
MySqlDataReader rdr = DB.CMD_f("SELECT * FROM tbl_kategorie");
int i = 0;
while (rdr.Read())
{
string str = rdr.GetString(1);
Console.WriteLine(str);
}
rdr.Close();
rdr.Connection.Close();
If you make the conn_f method public and don't call it in the CMD_f method, you can write much more robust code, that never leaves a connection or data reader hanging even if there is an error. That's a bigger change in the code, but definitely worth the effort when you have time to implement and test it. Using a using block to make sure that the objects are always disposed correctly makes the code much more resilient:
using (MySqlConnection conn = DB.conn_f()) {
using (MySqlDataReader rdr = DB.CMD_f(conn, "SELECT * FROM tbl_kategorie")) {
int i = 0;
while (rdr.Read()) {
string str = rdr.GetString(1);
Console.WriteLine(str);
}
}
}
Side note: Identifiers in C# tend to be descriptive. I suggest names like DB.CreateConnection and DB.ExecuteReader rather than DB.conn_f and DB.CMD_f.
i work with N tiers tec in C# for ado, trying to make it easy to use and capable to change any database kind with out write all the cod all over again ,
my code here doesn't get any error but it doesn't get any values to my textbox
(i am trying to get data from table to many textboxs to update it later)
and here how code works:{
at first i make some functions to take any set any kind of parameters or set any command and then i make other function to to execute what ever i set or get from database all that Function i build it in folder name (Data Access Layer)
then i made other folder (Data Build layer)to take use all those function for what ever i want to do in any page (insert , update , delete , Select),
the last think i do it to call the function i made at at (Data Build layer) to my page or control ,
i do all that because if i Change the database Type ,i change only one class and other classes still the same
i hope i explain enough (sorry for my English not good enough)}
Code :
Class DataAccessLayer
public static void Setcommand (SqlCommand cmd,CommandType type,string commandtext)
{
cmd.CommandType=type;
cmd.CommandText=commandtext;
}
public static void AddSQLparameter(SqlCommand cmd, int size,SqlDbType type,object value,string paramName,ParameterDirection direction)
{
if (cmd == null)
{
throw (new ArgumentException("cmd"));
}
if (paramName == null)
{
throw (new ArgumentException("paramName"));
}
SqlParameter param=new SqlParameter();
param.ParameterName= paramName;
param.SqlDbType=type;
param.Size=size;
param.Value=value;
param.Direction=direction;
cmd.Parameters.Add(param);
}
public static SqlDataReader ExecuteSelectCommand(SqlCommand cmd)
{
if (cmd == null)
{
throw (new ArgumentNullException("cmd"));
}
SqlConnection con = new SqlConnection();
cmd.Connection = con;
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
con.Close();
return dr ;
}
Class DatabuildLayer
SqlCommand com;
public DatabuildLayer()
{
com = new SqlCommand();
//
// TODO: Add constructor logic here
//
}
public SqlDataReader SelectCatalog(int catid)
{
DataAccessLayer.Setcommand(com, CommandType.Text, "select catname,catdescription,photo from category where catid=#catid" );
DataAccessLayer.addSQLparameter(com,16,SqlDbType.Int,catid,"#catid",ParameterDirection.Input);
return DataAccessLayer.ExecuteSelectCommand(com);;
}
and here my last code that retrieve my data to some textbox
in my Pageload :
protected void Page_Load(object sender, EventArgs e)
{
DatabuildLayer= new DatabuildLayer();
SqlDataReader dr ;
dr = obj.SelectCatalog(catselectddl.SelectedIndex);
if (dr.Read())
{
catnametxt.Text = dr["catname"].ToString();
catdestxt.Text = dr["catdescription"].ToString();
}
}
Is it possible that the query is returning nothing, and dr.Read() is returning false? Assuming the code actually executes (it is hard to tell from here) that is probably the only thing that would stop it working - either that or empty columns.
For what it is worth I think that your code needs to be tidied up a bit from a structural and conventions point of view. You should probably look through your code and consider the naming guidelines for the .NET framework. When others read your code they will want it formatted and consistent with this documentation. http://msdn.microsoft.com/en-us/library/xzf533w0(v=vs.71).aspx
Further, most people doing ASP.NET these days try to look for some way to inject external dependencies (such as databases) into their code using a framework like WebFormsMVP available at
http://webformsmvp.com/ in conjunction with an IoC container like autofac available at http://code.google.com/p/autofac/.
Using this approach you can push all external dependencies out of your application behind interfaces which would make it fairly trivial to plug in a different database engine.
Your current wrapper code is not doing anything particularly useful (just subsituting the existing methods or your own tht do the same thing), and it is not closing the connections correctly. It is... a bit of a mess.
If you aren't already massively familiar with the raw ADO.NET interfaces, then maybe consider something like "dapper" which will do all this for you, with a sane API:
short catid = 16;
using(var conn = GetOpenConnection()) {
var row = conn.Query(
"select catname,catdescription,photo from category where catid=#catid",
new { catid }).FirstOrDefault();
if(row != null) {
string name = row.catname, desc = row.catdescription;
// ...
}
}
Or if you have a class with CatName / CatDescription properties:
var obj = conn.Query<Catalogue>(
"select catname,catdescription,photo from category where catid=#catid",
new { catid }).FirstOrDefault();
from my experience, when you close a connection associated with a DataReader, nothing can be retrieved from the reader anymore.
//You closed the connection before returning the dr in the your method below:
public static SqlDataReader ExecuteSelectCommand(SqlCommand cmd)
{
if (cmd == null)
{
throw (new ArgumentNullException("cmd"));
}
SqlConnection con = new SqlConnection();
cmd.Connection = con;
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
con.Close(); //here your connection was already closed
return dr ; //this dr is disconnected
}
I have a Solution with multiple projects.
One project is my DataAccess project with 2 SQL CE databases defined, one for local users and one for company data, both with similar table structures. Public, static, readonly strings are defined for each database, and connections can be made.
Another project is my WPF project that will (eventually) display my data. To display data here, I have tried creating an Entity Context object, but nothing seems to work.
What is preventing me from accessing my data in the other project? (Currently, error states 'data source' is not defined)
How do I fix it?
AbcEntities abcContext;
public MainWindow() {
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
try {
EntityConnection ec = new EntityConnection(DataClass.AbcConnectionString);
abcContext= new AbcEntities(ec);
listbox1.ItemsSource = from c in abcContext.Customers select c;
abcCustomersBox.DisplayMemberPath = "Name";
} catch (Exception err) {
MessageBox.Show(err.Message);
}
}
For others, I found out how to do this.
In my static DataClass, I created the following routine to generate the Entity Connection String for me:
static string BuildEntityConnString(string dbFileName, string resourceData, string password) {
string resAll = #"res://*/";
string dataSource = #"Data Source=|DataDirectory|\" + dbFileName;
EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();
entityBuilder.Metadata = string.Format("{0}{1}.csdl|{0}{1}.ssdl|{0}{1}.msl", resAll, resourceData);
entityBuilder.Provider = "System.Data.SqlServerCe.3.5";
if (String.IsNullOrEmpty(password)) {
entityBuilder.ProviderConnectionString = dataSource;
} else {
entityBuilder.ProviderConnectionString = dataSource + ";Password=" + password;
}
using (EntityConnection con = new EntityConnection()) {
try {
con.ConnectionString = entityBuilder.ToString();
con.Open();
Console.WriteLine("{0} Entity String created.", dbFileName);
con.Close();
return con.ConnectionString;
} catch (Exception err) {
Console.WriteLine(err);
}
}
return null;
}
Notice that if there is any error, a NULL String is returned.
If anyone wants to use this, they should either place a breakpoint at the Exception, throw it, or handle it in some way. The Console.WriteLine() was just for me to debug through this.
I created Entity Connection Strings for my applications as follows:
public static readonly string EntityConnString =
BuildEntityConnString("sqlCeDb.sdf", "myModel", "abc123~Funky");
Hope others get some mileage out of this.
Explanation (more of an example, really) of how to create an EntityConnection can be found on MSDN here:
http://msdn.microsoft.com/en-us/library/bb738533.aspx
Looks pretty similar to what you have.