A static variable in static class asp.net mvc - c#

I have a static class Data:
public static class Data
{
public static SqlConnection connexion;
public static bool Connect()
{
System.Data.SqlClient.SqlConnectionStringBuilder builder = new System.Data.SqlClient.SqlConnectionStringBuilder();
builder["Initial Catalog"] = "Upload";
builder["Data Source"] = "base";
builder["integrated Security"] = true;
string connexionString = builder.ConnectionString;
connexion = new SqlConnection(connexionString);
try { connexion.Open(); return true; }
catch { return false; }
}
public static void Disconnect()
{
if (connexion != null) connexion.Close();
connexion = null;
}
}
in an the action Home :
public ActionResult Home()
{
Data.Connect();
if (CompteModels.Connected)
{
ArrayList model = new ArrayList();
ClientModels clients = new ClientModels();
model.AddRange(clients.Client_List());
AdminModels admins = new AdminModels();
model.AddRange(admins.Admin_List());
return View(model);
}
else return RedirectToAction("Login", "Account");
}
the client class:
public List<ClientModels> Client_List()
{
List<ClientModels> l = new List<ClientModels>();
using (Data.connexion)
{
string queryString = #"select Login, Password, Mail, Name, Tentatives from Compte where User_type_id in ( select Id from User_type where Fonction = 'Client')";
SqlCommand command = new SqlCommand(queryString, Data.connexion);
try
{
SqlDataReader reader = command.ExecuteReader();
do
{
while (reader.Read())
{
ClientModels admin = new ClientModels { Login = reader.GetString(0), Password = reader.GetString(1), Mail = reader.GetString(2), Name = reader.GetString(3), Tentatives = reader.GetInt32(4) };
l.Add(admin);
}
} while (reader.NextResult());
return l;
}
catch { return null; }
}
For the function AdminList, the implementation is the same like Client_List but in the class Admin.
The problem is in the static variable connexion : in the first function Client_List its value is correct and i get the list of the clients , but it's become null in the second function despite it is a static variable in static class !!!
What is the reason of this alteration ? How can i fix it?

You're either setting connexion to null somewhere or not initializing it before you use it.
Most likely, one class is calling Disconnect which sets connexion to null, while another class assumes it's not null and tries to use it.
As mentioned in the comments, keeping a static reference to a resource like a SqlConnection is not a good idea. If you want to re-use code you can create a static function that returns a new SqlConnection instance and make the connection string static, but having a static reference to a connection that's share across the entire web site will give you more problems that it's worth (as you're already seeing).
One way to do it in a static function would be:
public static SqlConnection GetConnection()
{
System.Data.SqlClient.SqlConnectionStringBuilder builder = new System.Data.SqlClient.SqlConnectionStringBuilder();
builder["Initial Catalog"] = "Upload";
builder["Data Source"] = "base";
builder["integrated Security"] = true;
string connexionString = builder.ConnectionString;
connexion = new SqlConnection(connexionString);
return connexion;
}
Your client code would then look something like:
using (SqlConnection conn = Data.GetConnection())

This is a bad idea, as others have already mentioned.
You should simply create and open a connection when needed, and dispose it afterwards:
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
// ... now use it
}
Of course, there are other patterns, that hide this mechanism, but that might be overkill in your case.

Your using statement disposes of the connexion using the IDisposable interface
public List<ClientModels> Client_List()
{
List<ClientModels> l = new List<ClientModels>();
using (Data.connexion) <--- here
}
Change this to create a new connection
public List<ClientModels> Client_List()
{
List<ClientModels> l = new List<ClientModels>();
using (var connection = Data.CreateConnexion())
}
similar to this
public static class Data
{
public static SqlConnection CreateConnection()
{
System.Data.SqlClient.SqlConnectionStringBuilder builder = new System.Data.SqlClient.SqlConnectionStringBuilder();
builder["Initial Catalog"] = "Upload";
builder["Data Source"] = "base";
builder["integrated Security"] = true;
string connexionString = builder.ConnectionString;
var connexion = new SqlConnection(connexionString);
connexion.Open();
return connexion;
}
}

Related

C# reusing my interfaces for database access

I am relatively new to c# and have only been a developer for a couple years. I followed this really great tutorial on how to make a library with data models and interfaces to handle retrieving and inserting data into my database. I am working on a Blazor server side application. I utilize my data access library by injecting its interface onto the razor page via a service created in the startup.cs. All of this works fantastically.
However, Now I am making class that reads delimited files and inserts the data into the database table. I would like to use the same interfaces in my data access library that I use to connect my razor pages to the back end.
Here is my class where I want to use the InsertPermit method from IpermitData to insert a record to my database table but _db is null and will give me a null reference exception when I run it. How can I get a handle on this interface so I can use it to insert data?
{
public class TextFileParser
{
public TextFileParser()
{
}
public void InsertTextFileData(string filePath)
{
string errMessage = string.Empty;
FileInfo file = new FileInfo(filePath);
if (!File.Exists(file.FullName))
{
errMessage = "File not found!";
}
else if (file.Length >= 0)
{
errMessage = "File has no data!";
}
IPermitData _db;
PermitModel permitRecord = new PermitModel();
string vText = string.Empty;
string[] vString;
string delimiter = "\t";
StreamReader fileReader = new StreamReader(filePath);
List<PermitModel> dt = new List<PermitModel>();
//dt.Add("Parcel Number");
//dt.Columns.Add("Permit ID");
//dt.Columns.Add("Construction Loc");
//dt.Columns.Add("Submission Date");
//dt.Columns.Add("Issue Date");
//dt.Columns.Add("Permit Type");
//dt.Columns.Add("Const. Addr.");
//dt.Columns.Add("EST Cost");
//dt.Columns.Add("Referrer");
//dt.Columns.Add("Comments");
//dt.Columns.Add("Status");
int header = 1;
while (!fileReader.EndOfStream)
{
if (header == 1)
{
header += 1;
vText = fileReader.ReadLine();
vString = vText.Split(delimiter, StringSplitOptions.None);
continue;
}
vText = fileReader.ReadLine();
vString = vText.Split(delimiter, StringSplitOptions.None);
permitRecord.PD_ParcelID = vString[0];
permitRecord.PD_Situs1 = vString[1];
permitRecord.PD_Owner = vString[2];
permitRecord.PD_Addr1 = vString[3];
permitRecord.PD_Addr2 = vString[4];
permitRecord.ADDR_3 = vString[5];
permitRecord.PD_City = vString[6];
permitRecord.PD_State = vString[7];
permitRecord.PD_Zip = vString[8];
permitRecord.Type_Construction = vString[9];
permitRecord.Estimated_Cost = vString[10];
permitRecord.Permit_Issue_Date = vString[11];
permitRecord.Permit_Type = vString[12];
permitRecord.Property_Type = vString[13];
permitRecord.Permit_NO = vString[14];
permitRecord.Completion_Date = vString[15];
permitRecord.Percent_Complete = vString[16];
permitRecord.Modified_Date = vString[17];
permitRecord.Note = vString[18];
permitRecord.Note_Date = vString[19];
permitRecord.Submission_Date = vString[20];
permitRecord.Submitter = vString[21];
permitRecord.Submitter_Phone = vString[22];
permitRecord.Submitter_Email = vString[23];
permitRecord.Land_AV = vString[24];
permitRecord.Impr_AV = vString[25];
permitRecord.Sec_Location = vString[26];
try
{
_db.InsertPermit(permitRecord);
}
catch (Exception)
{
// dt.Add(vString[0], vString[14], vString[1], vString[20], vString[11], vString[12], vString[26], vString[10], vString[21], vString[18], "Failed " + ex.Message);
//dt.Add(permitRecord);
continue;
}
//dt.Rows.Add(vString[0], vString[14], vString[1], vString[20], vString[11], vString[12], vString[26], vString[10], vString[21], vString[18], "Passed");
}
}
}
}
Here are the code files from my dataaccesslibrary.
public interface IPermitData
{
Task<List<PermitModel>> GetPermitData();
Task InsertPermit(PermitModel permit);
Task DeletePermit(PermitModel permit);
}
public class PermitData : IPermitData
{
private readonly ISqlDataAccess _db;
public PermitData(ISqlDataAccess db)
{
_db = db;
}
public Task<List<PermitModel>> GetPermitData()
{
string sql = "select * from dbo.I_Permit";
return _db.LoadData<PermitModel, dynamic>(sql, new { });
}
public Task InsertPermit(PermitModel permit)
{
string sql = #"insert into dbo.I_Permit ( Parcel, Location, Owner_Name, ADDR_1, ADDR_2, ADDR_3, City, State_Sh, Zipcode, Type_Construction, Estimated_Cost, Permit_Issue_Date, Permit_Type, Property_Type, Permit_NO, Completion_Date, Percent_Complete, Modified_Date, Note, Note_Date, Submission_Date, Submitter, Submitter_Phone, Submitter_Email, Land_AV, Impr_AV, Sec_Location, PD_Owner, PD_Name2, PD_Addr1, PD_Addr2, PD_City, PD_State, PD_Zip, PD_ControlNo, PD_ParcelID, PD_Situs1, PD_Situs2, PD_S_City, PD_S_State, PS_S_Zip )
values ( #Parcel, #Location, #Owner_Name, #ADDR_1, #ADDR_2, #ADDR_3, #City, #State_Sh, #Zipcode, #Type_Construction, #Estimated_Cost, #Permit_Issue_Date, #Permit_Type, #Property_Type, #Permit_NO, #Completion_Date, #Percent_Complete, #Modified_Date, #Note, #Note_Date, #Submission_Date, #Submitter, #Submitter_Phone, #Submitter_Email, #Land_AV, #Impr_AV, #Sec_Location, #PD_Owner, #PD_Name2, #PD_Addr1, #PD_Addr2, #PD_City, #PD_State, #PD_Zip, #PD_ControlNo, #PD_ParcelID, #PD_Situs1, #PD_Situs2, #PD_S_City, #PD_S_State, #PS_S_Zip )";
return _db.SaveData(sql, permit);
}
public Task DeletePermit(PermitModel permit)
{
string sql = #"DELETE FROM dbo.I_Permit WHERE Record_ID =' " + permit.Record_ID + " ';";
return _db.DeleteData(sql, permit);
}
}
public interface ISqlDataAccess
{
string ConnectionStringName { get; set; }
Task<List<T>> LoadData<T, U>(string sql, U parameters);
Task SaveData<T>(string sql, T parameters);
Task DeleteData<T>(string sql, T parameters);
}
public class SqlDataAccess : ISqlDataAccess
{
private readonly IConfiguration _config;
public string ConnectionStringName { get; set; } = "Default";
public SqlDataAccess(IConfiguration config)
{
_config = config;
}
public async Task<List<T>> LoadData<T, U>(string sql, U parameters)
{
string connectionString = _config.GetConnectionString(ConnectionStringName);
using (IDbConnection connection = new SqlConnection(connectionString))
{
var data = await connection.QueryAsync<T>(sql, parameters);
return data.ToList();
}
}
public async Task SaveData<T>(string sql, T parameters)
{
string connectionString = _config.GetConnectionString(ConnectionStringName);
using (IDbConnection connection = new SqlConnection(connectionString))
{
await connection.ExecuteAsync(sql, parameters);
}
}
public async Task DeleteData<T>(string sql, T parameters)
{
string connectionString = _config.GetConnectionString(ConnectionStringName);
using (IDbConnection connection = new SqlConnection(connectionString))
{
await connection.ExecuteAsync(sql, parameters);
}
}
}
welcome to the community! The nice thing about .Net core is it makes the dependency injection system work very smoothly. So in your constructor for your parser, you just need to inject what you need from your data access layer. An example with your PermitData class would look like this:
public class TextFileParser
{
private IPermitData _permitData;
public TextFileParser(IPermitData permitData)
{
this._permitData= permitData;
}
// code that uses your injected service
_permitData.MethodToDoWorkEtc();
}
Notice that in the constructor you call for the interface you need as I have it written, but you can also call for a concrete class if that is how your dependency injection is set up. It then populates a backing field in your class with the injected service, and you use the backing field as the start point to do the work that needs done.
The DI framework will pick this all up when you build your app and assemble it for you, so as long as the service is registered in the Startup.cs file, you shouldn't need anything else. This method will also allow you to compose simple services together into larger more advanced services while keeping the simple parts separated for better testing and portability.
Hope this helps!

The object does not connect to the server

I have this code:
public class Rabbit
{
public IConnection GetConnection(string hostName, string userName, string password)
{
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.HostName = "1.2.3.4";
connectionFactory.UserName = "login";
connectionFactory.Password = "pass";
connectionFactory.Port = 5672;
return connectionFactory.CreateConnection();
}
public void Send(string queue, string data)
{
using (IConnection connection = new ConnectionFactory().CreateConnection())
{
using (IModel channel = connection.CreateModel())
{
channel.QueueDeclare(queue, false, false, false, null);
channel.BasicPublish(string.Empty, queue, null, Encoding.UTF8.GetBytes(data));
}
}
}
public string Receive(string queue)
{
using (IConnection connection = new ConnectionFactory().CreateConnection())
{
using (IModel channelconsumer = connection.CreateModel())
{
channelconsumer.QueueDeclare(queue, false, false, false, null);
BasicGetResult result = channelconsumer.BasicGet(queue, true);
if (result != null)
{
string data = Encoding.UTF8.GetString(result.Body);
Console.WriteLine(data);
return data;
} else
{
return null;
}
}
}
}
}
I run my code:
var rabbit = new Rabbit();
rabbit.Send("sample.queue.queue", json);
My RABBIT object connects to the localhost, not the server whose configuration is in GetConnection.
Can I ask you to correct this code?
Login details are correct in my code.
It doesn't look like you consume the GetConnection method, you just create a completely separate ConnectionFactory which makes it use default values.
Looks like you should replace
using (IConnection connection = new ConnectionFactory().CreateConnection())
with
using (IConnection connection = GetConnection())

What's the proper way to set up a class to initialize public variables in c#?

I have created the class at the bottom in c#. This class is referenced by webservices to determine user accesses, like this:
[WebMethod]
public List<FAFSA> getFAFSA(string pageID)
{
formValues fv = new formValues();
string personID = fv.personID;
List<FAFSA> lf = new List<FAFSA>();
if (fv.secBlur == "no_secBlur")
{
FAFSA f = new FAFSA();
f.fafsaCheck = "0";
lf.Add(f);
}
...
}
I'm trying to add the two variables fafsa and staff. The method getSecBlur() is returning all three values from my database for secBlur, fafsa, and staff. So how do I set up this class, so that the SecBlur method is only called once but populates all three of my variables so that they can be used in webservice calls? It will not work the way it is now because it says fafsa and staff need to be static, but if I make them static, then in the webservices it says that the members must be accessed with an instance reference.
Sorry if this isn't worded to well, but I'm new to this and still trying to learn...
public class formValues : System.Web.Services.WebService
{
public string userName = getUserName();
public string firstName = getFirstName();
public string personID = getPersonID();
public int fafsa = 0;
public int staff = 0;
public string secBlur = getSecBlur();
private static string getUserDataString(int ix)
{
string retValue = "";
if (HttpContext.Current.Request.IsAuthenticated)
{
HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authCookie.Value);
if (ticket != null)
{
string[] userData = { "" };
char[] delimiterChar = { '|' };
userData = ticket.UserData.Split(delimiterChar);
if (userData.Length > 1)
retValue = userData[ix];
else
{
FormsAuthentication.SignOut();
string redirUrl = "/DMC/loginNotFound.html";
HttpContext.Current.Response.Redirect(redirUrl, false);
}
}
}
}
return retValue;
}
private static string getUserName()
{
//This retrieves the person logged into windows/active directory
WindowsPrincipal wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
//string[] fullUsername = wp.Identity.Name.Split('\\');
string fullUsername = wp.Identity.Name;
return fullUsername;
}
private static string getFirstName()
{
string firstName = getUserDataString(1);
return firstName;
}
private static string getPersonID()
{
string personID = getUserDataString(0);
return personID;
}
private static string getSecBlur()
{
string secBlur = "no_secBlur";
string mySQL = "exec get_UserAdminStatus #personID";
string cf = System.Configuration.ConfigurationManager.ConnectionStrings["DistrictAssessmentDWConnectionString"].ConnectionString;
SqlConnection connection = new SqlConnection(cf);
SqlCommand command = new SqlCommand(mySQL, connection);
command.Parameters.AddWithValue("#personID", getUserDataString(0));
connection.Open();
SqlDataReader dr = command.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(dr);
connection.Close();
if (dt.Rows.Count > 0)
{
if (dt.Rows[0]["secBlur"].ToString() == "1")
secBlur = "secBlur";
fafsa = Convert.ToInt32(dt.Rows[0]["fafsa"]);
staff = Convert.ToInt32(dt.Rows[0]["staff"]);
}
return secBlur;
}
}
If you give any class static, public values the so called "Static" (or type) Constructor will be called to do the initialization work before any access is done: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors
Another common way to do initlizsation or define default values, is to use the Factory Pattern. Afaik the Graphics Class in XNA has to adapt depending if you run ona X-Box or PC, so it uses the Factory Pattern.
Of coruse with Web(anything) there is the whole issue with variable Scope, even for Statics. Much less local variables.

SQLite.Net-PCL Connection not finding the DB

I've been trying to create a windows phone and I'd like to use SQLite to both store my data and learn how to use it on windows phone apps. For this purpose I'm using "SQLite.Net-PCL", but I keep getting a file not found exception. This the code I've written:
String ConnectionString = Path.Combine(ApplicationData.Current.LocalFolder.Path, Connection);
if (File.Exists(ConnectionString))
{
SQLite.Net.Platform.WindowsPhone8.SQLitePlatformWP8 e = new SQLite.Net.Platform.WindowsPhone8.SQLitePlatformWP8();
Con = new SQLiteConnection(e,ConnectionString);
}
else {
SQLite.Net.Platform.WindowsPhone8.SQLitePlatformWP8 e = new SQLite.Net.Platform.WindowsPhone8.SQLitePlatformWP8();
File.Create(ConnectionString);
Con = new SQLiteConnection(e, ConnectionString);
}
I thought maybe I get this error because I manually create an empty file but if that is the problem, how can I create a DB in case no database exists in the phone ?
You don't need to create the file yourself, as the SQLiteConnection constructor manages that for you.
public SQLiteConnection(ISQLitePlatform sqlitePlatform, string databasePath, bool storeDateTimeAsTicks = false, IBlobSerializer serializer = null)
: this(
sqlitePlatform, databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, storeDateTimeAsTicks, serializer)
{
}
So you should just open the connection, create the tables and that should be that.
class ExampleDataContext
{
public const string DATABASE_NAME = "data.sqlite";
private SQLiteConnection connection;
public TableQuery<Foo> FooTable { get; private set; }
public TableQuery<Bar> BarTable { get; private set; }
public ExampleDataContext()
{
connection = new SQLiteConnection(new SQLitePlatformWinRT(), Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, DATABASE_NAME));
Initialize();
FooTable = connection.Table<Foo>();
BarTable = connection.Table<Bar>();
}
private void Initialize()
{
connection.CreateTable<Foo>();
connection.CreateTable<Bar>();
}
}
Don't worry about that Initialize, the tables only get created when they're not there yet.

Types that own disposable fields should be disposable. how to solve this warning?

I tried using Run Code Analysis option in VisualStudio 2012, as a result of it I got a warning as
CA1001 Types that own disposable fields should be disposable
Implement IDisposable on 'DBConnectivity'
because it creates members of the following IDisposable types: 'SqlConnection', 'SqlCommand'.
I referred some question in SO, but I couldn't catch the point regarding IDisposable
and following is the class, responsible for this warning.
class DBConnectivity
{
public SqlConnection connection = null;
public SqlCommand command = null;
public SqlDataReader dataReader = null;
public string connectionString = null;
public List<MasterTableAttributes> masterTableList;
public DBConnectivity()
{
connectionString = ConfigurationManager.ConnectionStrings["Master"].ConnectionString;
connection = new SqlConnection(connectionString.ToString());
//-----Master table results
connection.Open();
string masterSelectQuery = "SELECT * FROM MASTER_TABLE";
command = new SqlCommand(masterSelectQuery, connection);
dataReader = command.ExecuteReader();
masterTableList = new List<MasterTableAttributes>();
while (dataReader.Read())
{
MasterTableAttributes masterTableAttribute = new MasterTableAttributes()
{
fileId = Convert.ToInt32(dataReader["Id"]),
fileName = Convert.ToString(dataReader["FileName"]),
frequency = Convert.ToString(dataReader["Frequency"]),
scheduledTime = Convert.ToString(dataReader["Scheduled_Time"])
};
masterTableList.Add(masterTableAttribute);
}
dataReader.Close();
connection.Close();
}
}
I am really confused in implementing the IDisposable. Any help appreciated?
I fully agree with the compiler - you need to dispose your fields here, or (as already noted) - not make them fields in the first place:
class DBConnectivity : IDisposable // caveat! read below first
{
public void Dispose() {
if(connection != null) { connection.Dispose(); connection = null; }
if(command != null) { command.Dispose(); command = null; }
if(dataReader != null) { dataReader.Dispose(); dataReader = null; }
}
Note that you would then use this type via using(...)
However! It looks like a static method would be more appropriate:
static class DBConnectivity
{
public static List<MasterTableAttributes> GetMasterTableList()
{
var connectionString = ConfigurationManager.ConnectionStrings["Master"].ConnectionString;
using(var connection = new SqlConnection(connectionString))
{
connection.Open();
const string masterSelectQuery = "SELECT * FROM MASTER_TABLE";
using(var command = new SqlCommand(masterSelectQuery, connection))
using(var dataReader = command.ExecuteReader())
{
var masterTableList = new List<MasterTableAttributes>();
while (dataReader.Read())
{
MasterTableAttributes masterTableAttribute = new MasterTableAttributes()
{
fileId = Convert.ToInt32(dataReader["Id"]),
fileName = Convert.ToString(dataReader["FileName"]),
frequency = Convert.ToString(dataReader["Frequency"]),
scheduledTime = Convert.ToString(dataReader["Scheduled_Time"])
};
masterTableList.Add(masterTableAttribute);
}
return masterTableList;
}
}
}
}
or perhaps simpler with a tool like "dapper":
static class DBConnectivity
{
public static List<MasterTableAttributes> GetMasterTableList()
{
var connectionString = ConfigurationManager.ConnectionStrings["Master"].ConnectionString;
using(var connection = new SqlConnection(connectionString))
{
connection.Open();
const string sql = "SELECT Id as [FileId], FileName, Frequency, Scheduled_Time as [ScheduledTime] FROM MASTER_TABLE";
return connection.Query<MasterTableAttributes>(sql).ToList();
}
}
}
If that is you complete class you should move all the SQL variables inside the constructor. Or perhaps change the constructor to a static function that return the masterTableList

Categories

Resources