I have a class library that contains hundreds of static methods and variable as follows…
public class General
{
public static string Con { get; set; }
public static string Func1()
{
using (SqlConnection con = new SqlConnection(Con))
{
// My stuff here
}
}
public static string Func2()
{
using (SqlConnection con = new SqlConnection(Con))
{
// My stuff here
}
}
public static string Funcn()
{
using (SqlConnection con = new SqlConnection(Con))
{
// My stuff here
}
}
}
I referenced this class library to my ASP.Net Webform app and assign connectionstring from Global.asax’s Application_Start event
protected void Application_Start(object sender, EventArgs e)
{
General.Con = ConfigurationManager.ConnectionStrings["Con"].ConnectionString;
}
Everything works fine.
Now that I wanted to change database connectionstring on per-LoggedIn-user basis.
What I have tried:
I stored all user’s connectionstring info at one table in common database and mapped them to respective userIDs.
On Login button click, I could save connectionstring to session.
Session["Con"] = ds.Tables[0].Rows[0][0].ToString();
In class library I used
Public static string Con = System.Web.HttpContext.Current.Session["Con"].ToString();
I get error : Object reference not set to an instance of an object.
If I remove static, all my variable and methods gives an error: An object reference is required for the non-static
If I use new keyword here, error is “Cannot be accessed with an instance reference; qualify it with a type name instead”.
Then I used
public static string Con()
{
string Con = "";
HttpContext httpContext = HttpContext.Current;
if (httpContext.ApplicationInstance.Session.Count > 0)
{
if (httpContext.ApplicationInstance.Session["Con"] != null)
Consd = httpContext.ApplicationInstance.Session["Con"].ToString();
}
return Con;
}
It gives me error: Cannot convert from method group to string
Please help me out…
Your class is static, which means there is a single instance, yet you want to change the connection on a user basis.
That is obviously not going to work. I would personally recommend you allow multiple instances of your class (non-static) and initialize each instance with the connection string as a parameter:
public class General
{
private string _connectionString;
public General(string connectionString)
{
_connectionString = connectionString;
}
}
You can then instantiate it once per session if you want, or simply instantiate it every time you need to use it. I would not recommend adding dependencies into the class (e.g. where the connection string comes to).
var data = new General(ds.Tables[0].Rows[0][0].ToString());
var result = data.Func1();
If for some reason, you need to keep the class static, you would need to either provide the connection string to the function so it can use it, or embed the logic to pull out the connection string from the session into the method:
public static string Func1(string connectionString)
{
using (SqlConnection con = new SqlConnection(connectionString))
{
// My stuff here
}
}
OR
public static string Func1()
{
using (SqlConnection con = new SqlConnection(ds.Tables[0].Rows[0][0].ToString()))
{
// My stuff here
}
}
I would recommend passing the connection string as a parameter if you decide to go this route.
One last option if you wish to keep your class static would be to use a Configurator object that provides the connection string, in order to abstract the location:
public interface IConfigurator
{
string GetConnectionString();
}
public class SessionConfigurator : IConfigurator
{
public string GetConnectionString()
{
var connectionString = Session["Con"].ToString();
return connectionString;
}
}
public static class General
{
public IConfigurator Configurator { get; set; }
public static string Func1()
{
using (SqlConnection con = new SqlConnection(Configurator.GetConnectionString()))
{
// My stuff here
}
}
}
Then upon application startup:
General.Configurator = new SessionConfigurator();
Related
I am trying to assign a value to a field variable, so that the value should be assigned to variable in the beginning, as that variable is needed in many methods, and i dont want to call method again and again in every method.
e.g
class MyClass
{
private string conn = "crms";
private string connectionString = myMethod(conn);
public string myMethod(string str)
{
// some code
}
}
but it gives me error, any help?
class MyClass
{
private string _conn = "crms";
private string _connectionString = myMethod(conn);
// Constructor
public MyClass()
{
connectionString = whatever _conn
}
}
Then you can do:
var myClass = new MyClass();
And the private variables will be set
You can either use #Prescott answer or you can modify it a little bit!
something like this:
private string _conn = "crms";
private string _connectionString = myMethod(conn);
// Constructor
public MyClass(string connection)
{
connectionString = whatever _conn
}
and you can use it like that:
var myClass = new MyClass("My Connection String");
if you're asking how to set a private field of a class using a method you can try this:
public string UpdateField(string conn)
{
_conn = conn;
return _conn;
}
this method will update your private field .. and you can delete the constructor if you don't need it.
I've created a method that acts as a factory to roll out the type of connection I need. In this case, I'm possibly instantiating types SqlConnection and PrincipalContext, and returning that instance. The method takes in a single parameter, type Object. If the parameter value is of the specified type above, it will create an instance of that object. My issue is the return type of the method is Object, so a cast is required when the method is called.
An example would be:
SqlConnection connection2 = new SqlConnection();
SqlConnection sqlCon = (SqlConnection)ConnectionFactory.RolloutConnectionType(connection2);
And the RolloutConnectionType method:
public static Object RolloutConnectionType(Object obj) {
if (obj == null) {
if (obj is PrincipalContext) {//create new PrincipalContext
string user, pass, domain;
domain = ConfigurationManager.AppSettings["SAdomain"];
user = ConfigurationManager.AppSettings["SAuser"];
pass = ConfigurationManager.AppSettings["SApass"];
obj = new PrincipalContext(ContextType.Domain, domain + ".mydomain.ca", "CN=MyCN,DC=myDC,DC=ca", user, pass);
} else if (obj is SqlConnection) {//create new SqlConnection
string connStr = System.Configuration.ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
obj = new SqlConnection(connStr);
}
}
return obj;
}
I think I'm on the right track with this, but it seems very messy and likely redundant with an instance required to create an instance - connection2 to create and return obj in RolloutConnectionType. It works, but I don't like how it works. Is what I'm attempting possible? Are there other avenues I could pursue?
Assuming you want to stick with the factory pattern, you should be looking at something like the following:
public interface Factory<T>
{
T Create();
}
public class PrincipalContextFactory : IFactory<PrincipalContext>
{
public PrinicipalContext Create()
{
// return new PrincipalContext(...);
}
}
public class SqlConnectionFactory : IFactory<SqlConnection>
{
public SqlConnection Create()
{
// return new SqlConnection(...);
}
}
Your factory shouldn't need anything more than to return a new instance of what you're after. You could go generics (Create<T>()), but now you're creating a bunch of edge cases for models not a PrinicpalContext or SqlConnection.
Why not just have your factory class with static methods of each thing your are trying to create and have each method return its own properly type-cast object
public static class YourFactory
{
public static SqlConnection GetConnection()
{
string connStr = System.Configuration.ConfigurationManager
.ConnectionStrings["MyConnectionString"].ConnectionString;
return new SqlConnection(connStr);
}
public static PrincipalContext GetPrincipalContext()
{
string user, pass, domain;
domain = ConfigurationManager.AppSettings["SAdomain"];
user = ConfigurationManager.AppSettings["SAuser"];
pass = ConfigurationManager.AppSettings["SApass"];
return new PrincipalContext(ContextType.Domain, domain + ".mydomain.ca",
"CN=MyCN,DC=myDC,DC=ca", user, pass);
}
}
I am a newbie. Sorry!
My Windows Form App has 3 layer. Presentation has Form_Login with textEdit_Name and textEdit_Pass.
My Connection class:
public class _Connection
{
public OleDbConnection GetConn(string _name, string _pass)
{
OleDbConnection _Conn = new OleDbConnection(String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};User ID={1};Password={2};", #"C:\Test\Test.mdb", _name, _pass));
return _Conn;
}
}
My Data Access Layer:
public class getDAL : IDisposable
{
private _Connection getConn = new _Connection();
OleDbConnection _Conn = new OleDbConnection();
public DataTable getDatatable()
{
_Conn = getConn.GetConn();
//Do something
}
}
How can I get _Conn with:
_name = textEdit_Name.Text and _pass = textEdit_Pass.Text
when user login through Form_Login
Perhaps the simplest method would be to set up the ConnectionString details in a static class in your DAL. Something like this:
public static class ConnectionDetails
{
public static string UserName;
public static string Password;
public static string GetAccessConnectionString(string filepath)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};", filepath);
if (string.IsNullOrEmpty(UserName) || string.IsNullOrEmpty(Password))
sb.Append("User Id=admin;Password=;");
else
sb.AppendFormat("User Id={0};Password={1};", UserName, Password);
return sb.ToString();
}
}
Your business layer needs to set the UserName and Password fields of the ConnectionDetails static class whenever they change in your presentation layer, and your DAL classes that need connection strings should get them by calling ConnectionDetails.GetAccessConnectionString with the appropriate file path. Or add FilePath as one of the static fields in that class so that you can set all three from wherever.
If you're intending to use more than one database file then a dictionary of connection data keyed off the file name would probably be a good idea.
You can use the ConnectionStringBuilder Class
public static class BuildConnection()
{
public static GetConnectionString(var userName, var Password)
{
OdbcConnectionStringBuilder builder = new OdbcConnectionStringBuilder();
builder.Driver = "Microsoft Access Driver (*.mdb)";
builder.Add("Dbq", #"C:\Test\Test.mdb");
builder.Add("User Id", userName);
builder.Add("Password", Password);
return builder.ConnectionString; // Here is your connection String
}
}
Here is example how you can pass LoginForm TextBox .Text to Business Layer and Data Access Layer.
Data Access Layer:
class DALClass : IDisposable
{
private _Connection getConn;
OleDbConnection _Conn;
public DALClass()
{
getConn = new _Connection();
}
public DataTable getDatatable(string sUserName, string sUserPass)
{
//pass on user name and password
_Conn = getConn.GetConn(sUserName, sUserPass);
//Do something
return default(DataTable); //return datatable
}
}
public class _Connection
{
public OleDbConnection GetConn(string _name, string _pass)
{
OleDbConnection _Conn = new OleDbConnection(String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};User ID={1};Password={2};", #"C:\Test\Test.mdb", _name, _pass));
return _Conn;
}
}
Business Layer:
class BLClass
{
DALClass _dal;
public BLClass()
{
_dal = new DALClass();
}
public DataTable GetDataTable(string sUserName, string sUserPass)
{
return _dal.getDatatable(sUserName, sUserPass);
}
}
Login Form:
public partial class LoginForm : Form
{
BLClass _bl;
public LoginForm()
{
InitializeComponent();
//object of business layer
_bl = new BLClass();
}
private void button1_Click(object sender, EventArgs e)
{
//pass text boxes values to Business Layer
DataTable dt = _bl.GetDataTable(textEdit_Name.Text, textEdit_Pass.Text);
}
}
I have a console application with a base class as following:
public abstract class PaymentSystemBase : IPayable
{
private SqlConnection _connection;
protected PaymentSystemBase()
{
CreateDatabaseConnection();
}
protected void CreateDatabaseConnection()
{
if(_connection == null)
{
string connectionString = ConfigurationManager.AppSettings["connString"];
var connection = new SqlConnection(connectionString);
_connection = connection;
connection.Open();
}
}
public SqlConnection Connection
{
get { return _connection; }
}
public abstract void ProcessPayment();
}
And have a few classes that derive from PaymentSystemBase:
public class PS1 : PaymentSystemBase
{
public override void ProcessPayment()
{
// Work with database using Connection from PaymentSystemBase
}
}
public class PS2 : PaymentSystemBase
{
public override void ProcessPayment()
{
// Work with database using Connection from PaymentSystemBase
}
}
In main program:
var lstPayments = new List<IPayable>
{
new PS1(),
new PS2()
};
var processPayments = new ProcessPayments(lstPayments);
processPayments.Process();
Where:
public class ProcessPayments
{
private List<IPayable> _paymentSystems;
public ProcessPayments(List<IPayable> paymentSystem)
{
_paymentSystems = paymentSystem;
}
public void Process()
{
foreach (var paymentSystem in _paymentSystems)
{
paymentSystem.ProcessPayment();
}
}
}
My question is how to use the same connection from PaymentSystemBase class and close it after processing? As I can see the connection was created again every time when PS1 and PS2 were created.
You shouldn't try to share the connection object. The connection objects themselves are actually quite lightweight, being an abstraction built on top of the actual physical connections, that the ADO.NET connection pool takes care of creating.
So you base class should be something like:
public abstract class PaymentSystemBase : IPayable
{
private static string _connectionString =
ConfigurationManager.ConnectionStrings["connString"].ConnectionString
public static string ConnectionString
{
get { return _connection; }
}
public abstract void ProcessPayment();
}
And then your derived classes should be:
public class PS1 : PaymentSystemBase
{
public override void ProcessPayment()
{
using(var conn = new SqlConnection(PaymentSystemBase.ConnectionString))
{
using(var cmd = new SqlCommand("...",conn)
{
//Prepare command
conn.Open();
cmd.ExecuteXXX();
//Process results, etc
}
}
}
}
You'll notice that I've also switched where the connection string is loaded from via the ConfigurationManager class from AppSettings to ConnectionStrings, which is a dedicated part of the configuration system for storing connection strings. This wasn't actually required but it is more conventional.
Here's my proposed (very simplified to illustrate the problem space) design for a C# console application. The database connections implement IDisposable, and this solution doesn't allow for using the database connection objects. Can someone propose a more correct structure for a console application? This is a problem I need to solve often.
class Program
{
SQLiteConnection sourceConnection;
SQLiteConnection destinationConnection;
static void Main(string[] args)
{
Program shell = new Program();
// get connection strings from command line arguments
string sourceConnectionString = shell.getConnectionString(args);
string destinationConnectionString = shell.getConnectionString(args);
// call non-static methods that use
shell.setUpConnections(sourceConnectionString, destinationConnectionString);
shell.doDatabaseWork();
}
private void setUpConnections(string sourceConnectionString, string destinationConnectionString)
{
sourceConnection = new SQLiteConnection(sourceConnectionString);
destinationConnection = new SQLiteConnection(destinationConnectionString);
}
private void doDatabaseWork()
{
// use the connections here
}
}
Edit:
Some people can't figure out why I'd want them as member variables. Here's my use case (a little psuedocoded) of what would go in doDatabaseWork:
foreach (Row sourceRow in DBResultSet)
{
string sourceXml = sourceRow.Columns["MyColumnName"].Value;
string destinationXML = transformUsingXSLT(sourceXml);
writeToDestination(destinationXml);
}
See how I'd want to keep these connections open for the life of this loop?
How about writing a class that implements IDisposable.
Inside your class constructor, you can instantiate your DB connections.
Then inside your IDisposable.Dispose Method, you write your tear down code for closing your DB connections.
Here is a code sample to demonstrate what I mean:
public class DBWrapper : IDisposable
{
public SqlConnection Connection1 { get; set; }
public SqlConnection Connection2 { get; set; }
public DBWrapper()
{
Connection1 = new SqlConnection();
Connection1.Open();
Connection2 = new SqlConnection();
Connection2.Open();
}
public void DoWork()
{
// Make your DB Calls here
}
public void Dispose()
{
if (Connection1 != null)
{
Connection1.Dispose();
}
if (Connection2 != null)
{
Connection2.Dispose();
}
}
}
And then, from within your main method of your Program class:
class Program
{
static void Main(string[] args)
{
using (DBWrapper wrapper = new DBWrapper())
{
wrapper.DoWork();
}
}
}
I think that the best solution is to extract main logic from Program class. The Program class is some kind of starter for primary work. And providing wrappers for SqlConnections is not a good idea indeed, because they are managed resources already, wrapping them is redundant. Thus my solution looks like this:
class ProgramCore : IDisposable
{
internal ProgramCore(string sourceConnectionString, string destinationConnectionString)
{
setUpConnections(sourceConnectionString, destinationConnectionString);
}
internal void Execute()
{
// do whatever you want
doDatabaseWork();
// do whatever you want
}
public void Dispose()
{
if (_sourceConnection != null)
_sourceConnection.Dispose();
if (_destinationConnection != null)
_destinationConnection.Dispose();
}
private void setUpConnections(string sourceConnectionString, string destinationConnectionString)
{
_sourceConnection = new SQLiteConnection(sourceConnectionString);
_destinationConnection = new SQLiteConnection(destinationConnectionString);
}
private void doDatabaseWork()
{
// use the connections here
}
private SQLiteConnection _sourceConnection;
private SQLiteConnection _destinationConnection;
}
class Program
{
static void Main(string[] args)
{
// get connection strings from command line arguments
string sourceConnectionString = GetConnectionString(args);
string destinationConnectionString = GetConnectionString(args);
using (ProgramCore core = new ProgramCore(sourceConnectionString, destinationConnectionString))
{
core.Execute();
}
}
static string GetConnectionString(string[] args)
{
// provide parsing here
}
}
Scott's answer is one way to do it. You could also consider using try{} finally instead?
static void Main(string[] args)
{
Program shell = new Program();
// get connection strings from command line arguments
string sourceConnectionString = shell.getConnectionString(args);
string destinationConnectionString = shell.getConnectionString(args);
// call non-static methods that use
shell.setUpConnections(sourceConnectionString, destinationConnectionString);
try
{
shell.doDatabaseWork();
}
finally
{
if(sourceConnection != null)
sourceConnection.Dispose();
if(destinationConnection != null)
destinationConnection.Dispose();
}
}
Personally, I think you are over thinking this and the code samples in this thread are overly complex imho. I have no idea why people are implementing IDisposable on their Program class either since it's disposed when it exits.
I can't think of a single reason to not use or why you cannot use the using(){} statement.
You want to open a Connection and hold it? Why? All the real connections are behind the scenes in .net connection pooling, so new'ing Connection objects is not a big deal. Just open and close as you need them and connection pooling handles all that behind the scenes.
I edited my example to wrap it in a class so you can have your encapsulation as well.
class Program
{
static void Main(string[] args)
{
DBWorker worker = new DBWorker();
worker.DoDatabaseWork();
}
}
public class DBWorker
{
private void DoDatabaseWork()
{
using (SQLiteConnection sourceDB = new SQLiteConnection( GetConnectionString() ))
{
sourceDB.Open();
using (SQLiteConnection destDB = new SQLiteConnection( GetConnectionString() ))
{
destDB.Open();
}
}
}
}
Hmm, I see no one has mentioned doing it this way. You don't have to have the variables that are used in the using declared locally.
class Program
{
SQLiteConnection sourceConnection;
SQLiteConnection destinationConnection;
static void Main(string[] args)
{
Program shell = new Program();
// get connection strings from command line arguments
string sourceConnectionString = shell.getConnectionString(args);
string destinationConnectionString = shell.getConnectionString(args);
using (sourceConnection = new SQLiteConnection(sourceConnectionString))
using (destinationConnection = new SQLiteConnection(destinationConnectionString))
{
shell.doDatabaseWork();
}
}
private void doDatabaseWork()
{
// use the connections here
}
}