Just finished my Winforms program for Clinics with database in sql managment Studio.
My Connection is ADO.NET Entity Data Model I mean edmx. I want to ask you guys what is next step and asking you if you see any injection problem
and how should I protect from Injection. All my code is Linq and I belive with Linq you get less problem of Injections.
My questions are three questions:
1) What kind of changes must I do in settings in my Visual project before deploying alaive on real server.
Is there any changes to do in Properity of my winforms Project? Becouse now this will be Production project.
2) My second question is, Do you see guys any lack of Security in my code when I add a new person, or when I search a person? And How should I do for the security sake?
See my some of my code below please
3) Is (ADO.NET Entity Data Model, ADO.NET Entity Data Model) normal to use for such kind of big system?
becouse my connectionstring is in App.config and it's very long string like this below and its geting me litle scared.. ;)
<add name="ClinicEntities" connectionString="metadata=res://*/MyHealthModel.csdl|res://*/MyHealthModel.ssdl|res://*/MyHealthModel.msl;provider=System.Data.SqlClient;provider connection string="data source=MyComputerName;initial catalog=ClinicDb;user id=***;password=*****;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" /></connectionStrings>
Here is some of my code:
When searching person:
private void SearchPatient()
{
try
{
using (ClinicEntities db = new ClinicEntities())
{
if(txtIdCardnr.Text != string.Empty)
{
string IdCard = txtIdCardnr.Text.Trim();
var patId = db.Patient.Where(x => x.IdentityCardNr == IdCard).FirstOrDefault();
if(patId != null)
{
var reservation = (from u in db.Registration
join p in db.Patient on u.PatientId equals p.PatientId
join ....... you got the idea
where ......
select new
{
ReservationNr = u.ReservNr,
ReservationDate = u.ReservationDate,
........
}
).ToList();
dgvReservations.DataSource = reservation;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
Exception inner = ex.InnerException;
while (inner != null)
{
MessageBox.Show(inner.Message);
inner = inner.InnerException;
}
}
}
And for adding new reservation:
private async void AddReservation()
{
try
{
using (ClinicEntities db = new ClinicEntities())
{
if (IsValidated())
{
Reservation pat = new Reservation();
pat.SymptomId = Convert.ToInt32(cmbSymptom.SelectedValue);
pat.SymptonDate = Convert.ToDateTime(dateTimePicker1.Value.Date);
pat.SymptonTime = txtTime.Text.Trim();
pat.Notes = txtNoteEmg.Text.Trim();
pat.RegisterdBy = StaffId;
pat.PatientId = PatientId;
db.Reservation.Add(pat);
await db.SaveChangesAsync();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
Exception inner = ex.InnerException;
while (inner != null)
{
MessageBox.Show(inner.Message);
inner = inner.InnerException;
}
}
}
So, du you see guys any lack of security in my code? Thank you again for helping me to get all three questions.
StackOverflow is not the place for code review (but there is a stack exchange site for code review and your question may be on topic there)
1) I'm not really sure how the server comes into this equation; surely it's only offering this winforms app for download, like any other file. No changes should be needed
2) I see an unencrypted plain text password in your config file, but whether you care or not is another matter. It could be that even if the user did open the local db with the password they found and have a look around they can't do any real damage. Now if that password is the same as your production server it might be more of an issue... The LINQ you have written to do your db access is immune to SQL injection. The only way to make it liable is to execute raw sql command that have had user provided values concatenated into them
3) I'm not sure StackOverflow is the place to seek help with a phobia of long connection strings. It works; leave it alone (other than encrypting the password maybe)
Related
I'm completely new to C# programming and I'm trying to learn on my own. Currently I'm building a mini-project to exercise.
I understand that the user layer should not have any data query for security reasons perhaps?
So I have created a separate Data Access class to retrieve data. This is what my data access class looks like(I'll be using stored procedures for better security once I learn how to use it):
public class DataAccess
{
public List<Customer> FilteredCustomersList(string name)
{
using (IDbConnection connection = new MySql.Data.MySqlClient.MySqlConnection(Helper.CnnVal("FineCreteDB")))
{
var output = connection.Query<Customer>($"SELECT * from `Customers` WHERE `Cust_Name` LIKE '{name}'").ToList();
return output;
}
}
Basically I send over a string from the user form to query the database, the data is retrieved and stored in a list. User form:
private void RetrieveData()
{
try
{
DataAccess db = new DataAccess();
filteredcustomers = db.FilteredCustomersList(CustomerNameTxtBox_AutoComplete.Text);
ntn_num = filteredcustomers.Select(x => x.Cust_NTN).ElementAt(0);
strn_num = filteredcustomers.Select(x => x.Cust_STRN).ElementAt(0);
address = filteredcustomers.Select(x => x.Cust_Address).ElementAt(0);
phone_num = filteredcustomers.Select(x => x.Cust_Phone).ElementAt(0);
id_num = filteredcustomers.Select(x => x.Cust_ID).ElementAt(0);
}
catch (Exception)
{
MessageBox.Show("Customer not found. If customer was recently added, try updating DB.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
DataAccess db = new DataAccess();
filteredcustomers = db.AllCustomersList();
ntn_num = "";
strn_num = "";
address = "";
phone_num = "";
}
}
On the user form side, "filteredcustomers" holds the list of data sent back, now here is the problem: I use the filteredcustomers list to extract the different column values like so:
address = filteredcustomers.Select(x => x.Cust_Address).ElementAt(0);
and then use them to populate the respective textboxes like:
Address_TxtBox.Text = address;
Everything works fine, but I don't want the userform to have these queries for all individual columns, because from what I've understood so far, this is bad programming and bad for security as well.
Can anyone guide me how I can keep the values in Data Access layer and just call them into my form?
I'm sorry if this is a long post, I'm just learning and wanted to be as detailed as possible.
You're already doing everything reasonably correctly as per how Dapper is to be used. Dapper doesn't maintain a local graph of entities from the db, track changes to it and automatically save them. If you want that, use something like EF
For dapper you retrieve data with a SELECT and send it back with an UPDATE
If you're only expecting one Customer for the name, do this:
var output = connection.QueryFirstOrDefault<Customer>($"SELECT * from `Customers` WHERE `Cust_Name` LIKE #n", new { n = name });
https://dapper-tutorial.net/queryfirst
This will return just one customer instance (or null; check it!) meaning you can tidy up your form code to:
c = db.FilteredCustomer(CustomerNameTxtBox_AutoComplete.Text);
ntn_num = c?.Cust_NTN;
strn_num = c?.Cust_STRN;
And so on
Your "if customer was recently added try updating db" doesn't really make sense- the query is done live, so the db is about as up to date as it can be
I'm trying to make a simple database insert for just one table, the insert and the connections are working perfectly.The problem appears only when the exceptions arise for entering bad data.
Here is my code: (using MySql and EF6)
using (MaintenanceDB db = new MaintenanceDB())
{
try
{
employee employee = new employee
{
ID = idTBA.textBox.Text,
EName = enTBA.textBox.Text,
AName = anTBA.textBox.Text,
CareerCode = careerCodeCBA.comboBox.SelectedItem.ToString(),
Specialization = specTBA.textBox.Text,
Mobile = mobileTBA.textBox.Text,
Telephone = teleTBA.textBox.Text,
Email = emailTBA.textBox.Text
};
db.employees.Add(employee);
db.SaveChanges();
}
catch (DbUpdateException exception)
{
MessageBox.Show(exception.InnerException.InnerException.Message);
}
catch (EntityException exception)
{
MessageBox.Show(exception.InnerException.Message);
}
}
so if the data entered correctly everything is smooth and fine, but if I entered duplicate ID for example the first time it's going to the first catch block and tell me there is a duplicate , at this point there is something wrong, it seems the connection isn't closed here (Despite using finally and dispose on db), the next time I hit the save button the error "Nested Transactions are not supported" appears, and then the db closes and I'm able to enter new data!
I tried opening the connection manually or starting a transaction and closing it manually as I found in few posts here but nothing seems to solve the problem
It seems like a mysql bug...., #71502
[27 Feb 15:54] Raif Atef
This bug is due to a bug in the MySqlTransaction class.
When I try to update my entry in update function it's execute successfully but database not updated.
Please find the following code
public static string UpdateEmployee(Employee employee)
{
using (var db = new RandDEntities())
{
var empObj = db.Employees.First(x => x.EmpID == employee.EmpID);
db.Entry(empObj).State = EntityState.Modified;
db.SaveChanges();
}
return "";
}
The problem is that you're saving the wrong entity (i.e. empObj) instead of the entity that has the changes (i.e. employee). Your code pulls empObj out of the database, and then turns around and saves it, without making any changes to it. You need to modify your code as follows:
public static string UpdateEmployee(Employee employee)
{
using (var db = new RandDEntities())
{
db.Employees.Attach(employee);
db.Entry(employee).State = EntityState.Modified;
db.SaveChanges();
}
return "";
}
That has absolutely nothing to do with Entity Framework but more with the fact that you likely use localdb and your database is not where you think it is, and reinitialized (reset) to empty every time you press start.
This question, in dozens of variants, gets asked over and overy by people not bothering to check where they look (and then realizing the database files have different paths).
I have developed a WCF api which is using nHibernate. I am new to this. I have used session.update to take care of transaction. I have a for loop in which based on select condition I am updating a record ie. If A is present in tabel1 then I am updating the table else inserting a new entry.
I am getting "could not execute query." when trying to execute a select query on a table which was previously being updated by adding a new entry in the table.
What I think is, because I am using session.save(table1) and then trying select entries from that table I am getting an error. Since session.save temporarily locks the table I am not able to execute a select query on that table.
What can be the solution on this?
Update:
This the for loop I am using to check in the database for some field:
using (ITransaction tranx = session.BeginTransaction())
{
savefunction();
tranx.Commit();
}
Save function:
public void savefunction()
{
for (int i = 0; i < dictionary.Count; i++)
{
ICandidateAttachmentManager candidateAttach = new ManagerFactory().GetCandidateAttachmentManager();
CandidateAttachment attach = new CandidateAttachment();
attach = checkCV();
if(attach == null)
{
//insert new entry into table attach
session.save(attach);
}
}
}
checkCV function:
public void checkCV()
{
using (ICandidateAttachmentManager CandidateAttachmentManager = new ManagerFactory().GetCandidateAttachmentManager())
{
IList<CandidateAttachment> lstCandidateAttachment = CandidateAttachmentManager.GetByfkCandidateId(CandidateId);
if (lstCandidateAttachment.Count > 0)
{
CandidateAttachment attach = lstCandidateAttachment.Where(x => x.CandidateAttachementType.Id.Equals(FileType)).FirstOrDefault();
if (attach != null)
{
return null;
}
else
{
return "some string";
}
}
}
}
What happening here is in the for loop if say for i=2 the attach value comes to null that I am entering new entry into attach table. Then for i=3 when it enters checkCV function I get an error at this line:
IList lstCandidateAttachment =
CandidateAttachmentManager.GetByfkCandidateId(CandidateId);
I think it is because since I am using session.save and then trying to read the tabel contents I am unable to execute the query and table is locked till I commit my session. Between the beginTransaction and commit, the table associated with the object is locked. How can I achieve this? Any Ideas?
Update:
I read up on some of the post. It looks like I need to set isolation level for the transaction. But even after adding it doesn't seem to work. Here is how I tried to inplement it:
using (ITransaction tranx = session.BeginTransaction(IsolationLevel.ReadUncommitted))
{
saveDocument();
}
something I don't understand in your code is where you get your nHibernate session.
Indeed you use
new ManagerFactory().GetCandidateAttachmentManager();
and
using (ICandidateAttachmentManager CandidateAttachmentManager = new ManagerFactory().GetCandidateAttachmentManager())
so your ManagerFactory class provides you the ISession ?
then you do:
CandidateAttachment attach = new CandidateAttachment();
attach = checkCV();
but
checkCV() returns either a null or a string ?
Finally you should never do
Save()
but instead
SaveOrUpdate()
Hope that helps you resolving your issue.
Feel free to give more details
I'm making a rather "simple" piece of software and at the moment I'm working with one table in my database and reading from the database works and now I was trying to implement inserting into the database, which seems to work as long as the program is running, but when I stop the program (stop debugging in VS) and launch it again, the rows don't seem to be in the database (already checked the .mdf database itself for the rows but they can't be found).
This is the piece of code:
public void saveKlant(klant nieuweKlant)
{
KlantGegevens newKlant = new KlantGegevens();
newKlant.klantNaam = nieuweKlant.naam;
newKlant.klantStraat = nieuweKlant.straat;
newKlant.klantPostcode = nieuweKlant.postcode;
newKlant.klantHuisNummer = nieuweKlant.huisnummer;
newKlant.klantGSM = nieuweKlant.gsm;
newKlant.klantTel = nieuweKlant.telnummer;
newKlant.klantGebDatum = nieuweKlant.gebDatum;
newKlant.klantEmail = nieuweKlant.email;
using (kapsalonEntities context = new kapsalonEntities())
{
try
{
context.KlantGegevens.AddObject(newKlant);
int test = context.SaveChanges();
}
catch
{
throw new InvalidOperationException("het object kon niet toegevoegd worden");
}
}
}
"test" equals 1 (so context.SaveCHanges() = 1) when running the program.
what would be the reason for the data to not be added persistently? since I do use a Context.SaveChanges()?
Thanks in advance.
It looks like you didn't check of the property where the database each time copies himself toi the debug directory. That's why you always get your default data again. Set the property to "if newer"