DB connection made in using statement - c#

In here it shows the error,some invalid argument
MyCode
static SqlConnection conDB = new SqlConnection(ConfigurationManager.ConnectionStrings["SiteSqlServer"].ConnectionString);
[WebMethod, ScriptMethod]
public static List<HomeImageSliders> GetHomeImageSliders()
{
List<HomeImageSliders> HomeImageList = new List<HomeImageSliders>();
try
{
using (SqlConnection con = new SqlConnection(conDB)) //<-- In here it shows the error
{
}

This is because you made a static DB connection, and tried to use it in the using.
Here is how you can fix this:
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["SiteSqlServer"].ConnectionString)) {
... // Your code goes here
}
Also remove the declaration of conDB - it is unnecessary.

SqlConnection does not have a constructor that takes another SqlConnection. Plus having a static SqlConnection is not a best practice. I suspect you want:
// make the _connection string_ static, not the _connection_
static string conDB = ConfigurationManager.ConnectionStrings["SiteSqlServer"].ConnectionString;
[WebMethod, ScriptMethod]
public static List<HomeImageSliders> GetHomeImageSliders()
{
List<HomeImageSliders> HomeImageList = new List<HomeImageSliders>();
try
{
using (SqlConnection con = new SqlConnection(conDB)) error
{
}

SqlConnection constructor accepts connection string, but not another SqlConnection.

Related

.NET Core Database The Connection String property has not been initialized

I'm trying to build a .NET 6 Core MVC application that shows a list of user records from the database.
But I'm getting the "The Connection String property has not been initialized" error when trying to open the connection.
Right now I'm trying to give the data in query string but getting this error.
**DATA ACCESS LAYER**
using ABL_USER_DebitCard_Info.Models;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
namespace ABL_USER_DebitCard_Info.Context
{
public class DebitCard_DAL
{
string connectionString = "Data Source = (localdb)\\MSSQLLocalDB; Initial Catalog = ABL_DebitCard_User_Info_DB";
public IEnumerable<Users> GetUserByCNIC(string? CNIC)
{
var debitcardList = new List<Users>();
using (SqlConnection conn = new SqlConnection())
{
SqlCommand cmd = new SqlCommand("ABL_GetUserByCNIC", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#CNIC", CNIC);
conn.Open(); ---> GETTING ERROR HERE
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
var user = new Users();
user.Id = Convert.ToInt32(reader["ID"].ToString);
user.CNIC = reader["CNIC"].ToString();
user.UserName = reader["UserName"].ToString();
user.CardNumber = reader["CardNumber"].ToString();
user.CardStatus = reader["CardStatus"].ToString();
debitcardList.Add(user);
}
conn.Close();
}
return debitcardList;
}
}
}
**Controller**
using ABL_USER_DebitCard_Info.Context;
using ABL_USER_DebitCard_Info.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace ABL_USER_DebitCard_Info.Controllers
{
public class UsersController : Controller
{
DebitCard_DAL dbcontext = new DebitCard_DAL();
[HttpGet]
public ActionResult Details(string CNIC)
{
if(CNIC == null)
{
return NotFound();
}
else
{
List<Users> debitcardList = dbcontext.GetUserByCNIC(CNIC).ToList();
return View(debitcardList);
if(debitcardList.Count == 0)
{
return NotFound();
}
else
{
return View(debitcardList);
}
}
}
}
}
You create the SqlConnection without providing any connection string.
Pass the connection string to the SqlConnection constructor
using (SqlConnection conn = new SqlConnection(connectionString ))
It's good that you have a variable called "connectionString", but don't forget to use it when you need to :)
When making a new instance of your sql connection you forgot to put it.
using (SqlConnection conn = new SqlConnection(connectionStringGoesHere))
connectionstring must mention in the startup.cs
use this or you can use dapper also to run the query in .net core
using (SqlConnection conn = new SqlConnection(connectionString)

C# method returns connect to different databases

UPD:
I have a static class for work with database.
This class contains the method which returns connect to database. Early this method returns connect to Advantage database (AdsConnection):
static private AdsConnection GetConnection(){
var conn = new AdsConnection();
conn.ConnectionString = here my connection string
return conn;
}
Now, I need to change this method. I need that this method returns connect to different databases types (Advantage database, Oracle database).
The method will work into public methods in my class. For example, method for get data from any table from database.
public static List<entity1> GetEntities(){}
Into this method the first of my step is to resolve the type of database, then connect to database. Then get data from database and the last step is return data (List< entity1 >).
In the step to connect the database I need to use the method GetConnection("Ads")
This method returns current connect to database and then I can use this connect for work
I changed method:
My first version
static private T GetConnection<T>(string dbType)
{
if (dbType.Equals("Oracle"))
{
OdbcConnection conn = new OdbcConnection
conn.ConnectionString = here my connection string
return (T)conn;
}
if (dbType.Equals("Ads"))
{
AdsConnection conn = new AdsConnection
conn.ConnectionString = here my connection string
return (T)conn;
}
return default(T);
}
But, my solution does not work. I have errors:
Cannot convert type 'System.Data.Odbc.OdbcConnection' to 'T'
Cannot convert type 'Advantage.Data.Provider.AdsConnection' to 'T'
I do not know how to resolve my problem.
Please, tell me how to resolve my problem?
Now, I use the following code (this solution give me #khlr):
static private IDbConnection GetConnection(string dbType)
{
if (dbType.Equals("Oracle"))
{
OdbcConnection conn = new OdbcConnection
conn.ConnectionString = here my connection string
return conn;
}
if (dbType.Equals("Ads"))
{
AdsConnection conn = new AdsConnection
conn.ConnectionString = here my connection string
return conn;
}
return null;
}
Thank.
One way you can abstract the connection instantiation is by using DbProviderFactory of ADO.Net. You can basically pass it a provider name and it will give a connection based on the provider. This basically reduce the check of dbtype etc for you and I think its sensible approach when you need to target multiple database. Some of the code snippet are copied from MSDN.
In you config file you can multiple connection string set up with different database type and provider.
<configuration>
<add name="NorthwindAccess"
providerName="System.Data.OleDb"
connectionString=
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Data\Northwind.mdb;"
/>
Then in you method you can do following:
static DbConnection CreateDbConnection(
string providerName, string connectionString)
{
// Assume failure.
DbConnection connection = null;
// Create the DbProviderFactory and DbConnection.
if (connectionString != null)
{
try
{
DbProviderFactory factory =
DbProviderFactories.GetFactory(providerName);
connection = factory.CreateConnection();
connection.ConnectionString = connectionString;
}
catch (Exception ex)
{
// Set the connection to null if it was created.
if (connection != null)
{
connection = null;
}
Console.WriteLine(ex.Message);
}
}
// Return the connection.
return connection;
}
You could do the following, since both connections inherit from IDbConnection:
static private IDbConnection GetConnection(string dbType)
{
if (dbType.Equals("Oracle"))
{
OdbcConnection conn = new OdbcConnection
conn.ConnectionString = here my connection string
return conn;
}
if (dbType.Equals("Ads"))
{
AdsConnection conn = new AdsConnection
conn.ConnectionString = here my connection string
return conn;
}
return null;
}

SqlConnection by Method

I'm trying to implement a method that will provide the SqlConnection, how should I do it?
public class DAL
{
public bool dbCon()
{
string comboValue;
try
{
using (SqlConnection sqlConn =
new SqlConnection(#"Data Source =VirtualXP-64805;Initial Catalog=CTS_Demo;Integrated Security=SSPI"))
{
sqlConn.Open();
}
}
catch (SqlException Ex)
{
MessageBox.Show(Ex.ToString());
}
}
}
You method should return the connection object not a bool value, or you may define a class level connection variable and use that.
But When it comes to Database Connection then open it as late as possible and close it as early as possible
Instead of opening the connection from the method you may simply return the connection object and open it where you need it. Something like:
public SqlConnection dbCon()
{
return new SqlConnection(#"Data Source =VirtualXP-64805;Initial Catalog=CTS_Demo;Integrated Security=SSPI");
}
and then where you are using it:
using(SqlConnection conn = dbCon())
{
conn.Open();
.... your code
}
Or you can get rid of the method and simply call the new SqlConnection with connection string from the configuration.
EDIT:
Since you want to return an open connection from your method, you can do the following, but IMO its not the recommended way, you have to call Dispose manually for each connection object, since you will not use it within using statement.
public SqlConnection dbCon()
{
SqlConnection sqlConn;
try
{
sqlConn = new SqlConnection(#"Data Source =VirtualXP-64805;Initial Catalog=CTS_Demo;Integrated Security=SSPI")
}
catch(SqlException)
{
//your exception handling details
sqlConn = null;
}
return sqlConn;
}

Avoid enabling MSDTC when using TransactionScope

[Using: C# 3.5 + SQL Server 2005]
I have some code in the Business Layer that wraps in a TransactionScope the creation of an order and its details:
DAL.DAL_OrdenDeCompra dalOrdenDeCompra = new GOA.DAL.DAL_OrdenDeCompra();
DAL.DAL_ItemDeUnaOrden dalItemDeUnaOrden = new GOA.DAL.DAL_ItemDeUnaOrden();
using (TransactionScope transaccion = new TransactionScope())
{
//Insertion of the order
orden.Id = dalOrdenDeCompra.InsertarOrdenDeCompra(orden.NumeroOrden, orden.PuntoDeEntregaParaLaOrden.Id, (int)orden.TipoDeCompra, orden.FechaOrden, orden.Observaciones);
foreach (ItemDeUnaOrden item in orden.Items)
{
//Insertion of each one of its items.
dalItemDeUnaOrden.InsertarItemDeUnaOrden(orden.Id, item.CodigoProductoAudifarma, item.CodigoProductoJanssen, item.CodigoEAN13, item.Descripcion, item.CantidadOriginal, item.ValorUnitario);
}
transaccion.Complete();
}
return true;
And here is the DAL code that perform the inserts:
public int InsertarOrdenDeCompra(string pNumeroOrden, int pPuntoEntregaId, int pTipoDeCompra, DateTime pFechaOrden, string pObservaciones)
{
try
{
DataTable dataTable = new DataTable();
using (SqlConnection conexion = new SqlConnection())
{
using (SqlCommand comando = new SqlCommand())
{
ConnectionStringSettings conString = ConfigurationManager.ConnectionStrings["CSMARTDB"];
conexion.ConnectionString = conString.ConnectionString;
conexion.Open();
comando.Connection = conexion;
comando.CommandType = CommandType.StoredProcedure;
comando.CommandText = "GOA_InsertarOrdenDeCompra";
//...parameters setting
return (int)comando.ExecuteScalar();
...
public int InsertarItemDeUnaOrden(int pOrdenDeCompraId, string pCodigoProductoAudifarma, string pCodigoProductoJanssen, string pCodigoEAN13, string pDescripcion, int pCantidadOriginal, decimal pValorUnitario)
{
try
{
DataTable dataTable = new DataTable();
using (SqlConnection conexion = new SqlConnection())
{
using (SqlCommand comando = new SqlCommand())
{
ConnectionStringSettings conString = ConfigurationManager.ConnectionStrings["CSMARTDB"];
conexion.ConnectionString = conString.ConnectionString;
conexion.Open();
comando.Connection = conexion;
comando.CommandType = CommandType.StoredProcedure;
comando.CommandText = "GOA_InsertarItemDeUnaOrden";
//... parameters setting
return comando.ExecuteNonQuery();
Now, my problem is in the items insertion; when the InsertarItemDeUnaOrden tries to open a new connection an exception is rised because that would cause the TransactionScope to try promoting to MSDTC, wich I don't have enabled and I would prefer not to enable.
My doubts:
Understandig that the method tht starts the transaction is in the business layer and I don't want there any SqlConnection, ¿can I use another design for my data access so I'm able to reuse the same connection?
Should I enable MSDTC and forget about it?
Thanks.
EDIT: solution
I created a new class in the DAL to hold transactions like this:
namespace GOA.DAL
{
public class DAL_Management
{
public SqlConnection ConexionTransaccional { get; set; }
public bool TransaccionAbierta { get; set; }
public DAL_Management(bool pIniciarTransaccion)
{
if (pIniciarTransaccion)
{
this.IniciarTransaccion();
}
else
{
TransaccionAbierta = false;
}
}
private void IniciarTransaccion()
{
this.TransaccionAbierta = true;
this.ConexionTransaccional = new SqlConnection();
ConnectionStringSettings conString = ConfigurationManager.ConnectionStrings["CSMARTDB"];
this.ConexionTransaccional.ConnectionString = conString.ConnectionString;
this.ConexionTransaccional.Open();
}
public void FinalizarTransaccion()
{
this.ConexionTransaccional.Close();
this.ConexionTransaccional = null;
this.TransaccionAbierta = false;
}
}
}
I modified the DAL execution methods to receive a parameter of that new class, and use it like this:
public int InsertarItemDeUnaOrden(int pOrdenDeCompraId, string pCodigoProductoAudifarma, string pCodigoProductoJanssen, string pCodigoEAN13, string pDescripcion, int pCantidadOriginal, decimal pValorUnitario, DAL_Management pManejadorDAL)
{
try
{
DataTable dataTable = new DataTable();
using (SqlConnection conexion = new SqlConnection())
{
using (SqlCommand comando = new SqlCommand())
{
if (pManejadorDAL.TransaccionAbierta == true)
{
comando.Connection = pManejadorDAL.ConexionTransaccional;
}
else
{
ConnectionStringSettings conString = ConfigurationManager.ConnectionStrings["CSMARTDB"];
conexion.ConnectionString = conString.ConnectionString;
conexion.Open();
comando.Connection = conexion;
}
comando.CommandType = CommandType.StoredProcedure;
comando.CommandText = "GOA_InsertarItemDeUnaOrden";
And finally, modified the calling class:
DAL.DAL_OrdenDeCompra dalOrdenDeCompra = new GOA.DAL.DAL_OrdenDeCompra();
DAL.DAL_ItemDeUnaOrden dalItemDeUnaOrden = new GOA.DAL.DAL_ItemDeUnaOrden();
using (TransactionScope transaccion = new TransactionScope())
{
DAL.DAL_Management dalManagement = new GOA.DAL.DAL_Management(true);
orden.Id = dalOrdenDeCompra.InsertarOrdenDeCompra(orden.NumeroOrden, orden.PuntoDeEntregaParaLaOrden.Id, (int)orden.TipoDeCompra, orden.FechaOrden, orden.Observaciones, dalManagement);
foreach (ItemDeUnaOrden item in orden.Items)
{
dalItemDeUnaOrden.InsertarItemDeUnaOrden(orden.Id, item.CodigoProductoAudifarma, item.CodigoProductoJanssen, item.CodigoEAN13, item.Descripcion, item.CantidadOriginal, item.ValorUnitario, dalManagement);
}
transaccion.Complete();
}
dalManagement.FinalizarTransaccion();
With this changes I'm inserting orders and items without enabling MSDTC.
When using TransactionScope with multiple connections against SQL Server 2005, the transaction will always escalate to a distributed one (meaning MSDTC will be used).
This is a known issue, fixed in SQL Server 2008.
One option you have is to write a single stored procedure that does all the required operations (folding up GOA_InsertarOrdenDeCompra and all calls GOA_InsertarItemDeUnaOrden). With SQL Server 2005 this can be accomplished with an XML parameter, though SQL Server 2008 (apart from not having this issue) has table-valued parameters.
Can't you create the connection outside the methods and pass the same connection to both methods through the parameters?
That way you use the same connection avoiding the promotion.
My good solution would be to rethink the architecture of the DAL.
Something like having an central DAL, that stores an connection object, and have an reference to your DAL_OrdenDeCompra and DAL_ItemDeUnaOrden objects, and passing the reference of the DAL to this objects so they can interact with the connection stored in the DAL.
And then the DAL could have an Open and Close method with reference count, open increments, close decrements and it should only dispose the connection when it reaches zero and create a new one when incrementing to one. Also the DAL should implement the IDisposable to clean the resources of the connection. Then in your Business Layer you do something like this:
using(DAL dal = new DAL())
{
DAL.DAL_OrdenDeCompra dalOrdenDeCompra = dal.OrdenDeCompra;
DAL.DAL_ItemDeUnaOrden dalItemDeUnaOrden = dal.ItemDeUnaOrden;
using (TransactionScope transaccion = new TransactionScope())
{
dal.Open();
//Insertion of the order
orden.Id = dalOrdenDeCompra.InsertarOrdenDeCompra(orden.NumeroOrden, orden.PuntoDeEntregaParaLaOrden.Id, (int)orden.TipoDeCompra, orden.FechaOrden, orden.Observaciones);
foreach (ItemDeUnaOrden item in orden.Items)
{
//Insertion of each one of its items.
dalItemDeUnaOrden.InsertarItemDeUnaOrden(orden.Id, item.CodigoProductoAudifarma, item.CodigoProductoJanssen, item.CodigoEAN13, item.Descripcion, item.CantidadOriginal, item.ValorUnitario);
}
transaccion.Complete();
}
return true;
}
You could have a method in DAL.DAL_ItemDeUnaOrden which receives a collection of ItemDeUnaOrden instead of a single item, that way you can use a SqlTransaction (or TransactionScope) and iterate over the items within the DA method.
orden.Id = dalOrdenDeCompra.InsertarOrdenDeCompra(...);
dalItemDeUnaOrden.InsertarVariosItemsDeUnaOrden(orden.Items);
Depending on your code, you might not have access to your busiess objects (ItemDeUnaOrden) within you DAL, so you might need to pass the values some other way, maybe DTOs or a DataTable.

how do I setup the Connection String where I only change it one place?

How can I make the code
string connStr = ConfigurationManager.ConnectionStrings "staceys_cakesConnectionString"].ConnectionString;
work generically and not need the staceys_cakesConnectionString? Or how can I set it somewhere else so I only have to change it one place when I change it?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
namespace SC1.Models.DAL
{
public class CategoryDAL
{
public CategoryDAL()
{
}
string connStr = ConfigurationManager.ConnectionStrings["staceys_cakesConnectionString"].ConnectionString;
// select all
public DataSet Select()
{
SqlConnection sqlConnection1 = new SqlConnection();
string SqlString = "select * from Categories";
SqlDataAdapter da = new SqlDataAdapter(SqlString, connStr);
DataSet ds = new DataSet();
da.Fill(ds, "Categories");
return (ds);
}
// save
// insert
// update
// delete
}
}
Example of a page function I have how can I make this one better using your suggestion #Adam or anyone else?
// List
public List<page> Select()
{
List<page> _list = new List<page>();
string SqlStatement = "select * from Pages";
SqlConnection thisConnection = new SqlConnection(connStr);
// Open the Connection
thisConnection.Open();
var thisCommand = thisConnection.CreateCommand();
thisCommand.CommandText = SqlStatement;
SqlDataReader thisReader = thisCommand.ExecuteReader();
while (thisReader.Read())
{
// Create a new instance of the Current Page Object
page currentPage = new page();
// Fill the instance of the Current Page Object
currentPage.PageID = Convert.ToInt32(thisReader["PageID"]);
currentPage.ParentID = Convert.ToInt32(thisReader["ParentID"]);
currentPage.CategoryID = Convert.ToInt32(thisReader["CategoryID"]);
currentPage.Name = thisReader["Name"].ToString();
currentPage.PageHTMLContent = thisReader["PageHTMLContent"].ToString();
currentPage.NavigationText = thisReader["NavigationText"].ToString();
currentPage.TopMenu = Convert.ToBoolean(thisReader["TopMenu"]);
currentPage.SubMenu = Convert.ToBoolean(thisReader["SubMenu"]);
currentPage.DisplayOrder = Convert.ToInt32(thisReader["DisplayOrder"]);
currentPage.Active = Convert.ToBoolean(thisReader["Active"]);
// Add the instance of the Current Page Object to the List<>.
_list.Add(currentPage);
}
// Close the Database
thisConnection.Close();
return _list;
}
Just use a constant. For that matter, just use a static property and obtain the string that way.
public static class ConnectionStrings
{
public static string StacyesCakes
{
get
{
ConfigurationManager.ConnectionStrings[
"staceys_cakesConnectionString"].ConnectionString;
}
}
}
That will allow you to do things like:
using(var conn = new SqlConnection(ConnectionStrings.StaceysCakes))
{
...
}
Or (just adapting your existing code):
public DataSet Select()
{
SqlConnection sqlConnection1 = new SqlConnection();
string SqlString = "select * from Categories";
SqlDataAdapter da=new SqlDataAdapter(SqlString,ConnectionStrings.StaceysCakes);
DataSet ds = new DataSet();
da.Fill(ds, "Categories");
return (ds);
}
(You don't need sqlConnection1; you're not using it anywhere).
Note, however, that because SqlDataAdapter implements IDisposable and you're finished with it after this code executes, you should enclose it in a using block.
I would rewrite your function to something like this:
public DataSet Select()
{
using(SqlDataAdapter da = new SqlDataAdapter(
"select * from Categories",
ConnectionStrings.StaceysCakes))
{
DataSet ds = new DataSet();
da.Fill(ds, "Categories");
return ds;
}
}
It is a good idea to use a const in a class that is commonly used in your DataLayer:
public class CategoryDAL
{
public const string connStringName = "staceys_cakesConnectionString";
// the rest
}
and use the identifier connStringName everywhere in your class.
I have made it public so that it is available outside of the class as CategoryDAL.connStringName but that will rarely be necessary.
That may seem a little like only shifting the problem, but you get good intellisense and refactoring support.
Depending on your application type, put it in an app.config or web.config file. Then you can use the ConfigurationManager class to access it.
Here's a helpful link
You could save the ConnectionString on your application configuration file. The next link explains more about it.
Connection String

Categories