I have a VSTO addin. Right now I am hard coding two dictionaries for development. They need to persist so I am going to use mssql. I have created the tables and all, so everything is done on that end. But I'm having some trouble getting a few things to work so I have a few questions:
First, is it possible to use Windows Forms in VSTO to create a CRUD form for the database tables? There are 2 tables and they aren't too long.
Next, when connecting with SqlConnection, the example connection strings I am seeing don't make any sense. Here is an example: tmpConn = new SqlConnection("server=(local)\\SQLEXPRESS;Trusted_Connection=yes"); I'm not sure how to make the connection string. Right now my db is a local mssql instance, but in the future it will be hosted on a local network server. It says SQLEXPRESS now, is that the same as mssql? If not how can I change it to mssql? How do I construct the correct string for mssql and how do I authenticate? Is it done in the connection string or somewhere else?
Next to Last, is there an easy way to query a database with 3 columns, ID (PK), domain, and dirname. And place domain and dirname into a dict where domain is the key and dirname the value, the ID is uneeded for this.
Here is what I have so far:
public void retrieveClient(SqlConnection conn)
{
try
{
using (conn)
{
SqlCommand command = new SqlCommand(
"SELECT ClientDirName, ClientEmailDomain FROM ClientTable;",
conn);
conn.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
string clientDir = reader.GetString(0);
string clientEmail = reader.GetString(1);
clientDict.Add(clientEmail, clientDir);
}
}
else
{
MessageBox.Show("No rows found in ClientTable", "Rows Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
reader.Close();
}
}
catch (InvalidOperationException ex)
{
MessageBox.Show(String.Format("Exception while accessing ClientTable: {0}", ex), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (SqlException ex)
{
MessageBox.Show(String.Format("Exception while accessing ClientTable: {0}", ex), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
And finally, the part where it says string clientDir = reader.GetString(0) and string clientEmail = reader.GetString(1) Will it return the correct values here? The table has 3 values as I said, ID, Dir, and Email. But as you can see my SqlCommand only selects ClientDirName and ClientEmailDomain. Does this mean the GetString() methods will return those with 0 and 1? Or would it be 1 and 2 since ID is 0? I'm not sure how it works, does reader.GetString() base the indexes off the actual table or the SqlCommand?
I also wanted to know if the while (reader.Read()) part will add each row one by one so that my clientDict.Add() would work properly or not.
If it possible to do CRUD with a database with windows forms please give me some guidance or a small example. Other than that I just need my code examined to make sure it's doing what I want. I've been trying to test it but there are a lot of other missing pieces at the moment so I need assistance.
Any assistance would be much appreciated. And if someone could provide a few small example connection strings for both local and network mssql servers that require authentication it would be a huge help. I've been looking everywhere and can't get this working. I've heard EF could do it but I can't find a single example or guide that does what I need. If someone could share one that may help too, if you with EF is the way to go.
Thanks in advance!
You may treat your VSTO based add-in as a regular .Net application. There is no anything specific from the Db perspective. The only difference is that your VSTO assembly is run within the host application (not standalone). So, I'd suggest reading any good book on how to use SQL databases (ADO.NET) in .net applications or use EF (Entity Frameworks) first. It will give you the answer to all your questions.
Related
If user puts any username or password from the database it logs in. It doesn't crossmatch between the index of them. I'm working on this as a beginner learner.
if(txtusername.Text != null && txtpassword.Text != string.Empty)
{
sql = string.Format(#" select * from idpass where username ='{0}' ", txtusername.Text );
DataTable dtForNameAndRole = LoadDataByQuery(sql);
if(dtForNameAndRole.Rows.Count > 0)
{
sql = string.Format(#" select * from idpass where password ='{0}' ", txtpassword.Text);
DataTable dtForNameAndRole2 = LoadDataByQuery(sql);
if (dtForNameAndRole2.Rows.Count > 0)
{
sql = string.Format(#" select * from idpass where username = '{0}' and password ='{0}' ", txtusername.Text, txtpassword.Text);
DataTable dtForNameAndRole3 = LoadDataByQuery(sql);
Response.Redirect("Dashboard.aspx");
}
else
{
lblMessage.Text = "No Such Password";
}
}//end of if
else
{
lblMessage.Text = "no such user";
}
}
else
{
msgtr.Visible = true;
lblMessage.Text = "Sorry! Invalid user name or password.";
lblMessage.ForeColor = Color.Red;
return;
}
There are lot of issues in your existing code.
You should not store the plain password in the database.
There is no need of calling the query 3 times. Only one time is sufficient.
You should not query only on password because passwords can be same for many users.
Don’t use * in the select query. You should use the columns as aliases.
Put the breakpoint and debug your code to see what is the query you’re calling. This way you will get to know whether your query is correct or not. And you can run this query in the database as well to check whether it’s working as expected or not.
As suggested by #Larnu, please use parameterized query to prevent the sql injection. You can refer this article for the concept.
as noted, this is for learning. However, VERY important to realize that you want to use the "built in system" for logons. The reasons are too long for this post. But by using the defined built in logon system?
Then you can use the pre-made templates for logons.
You can setup security using IIS (internet services), and NOT have to hand code out a WHOLE web based security system. This will save I can figure about a whole month of solid work. And if you use the built in logon system?
Then you can even drop into a page the asp.net logon control - and it will do all the magic and coding for you - in other words, there is a HUGE system working behind the scenes to manage security and logons for you. In a nutshell?
Don't try and roll your own security system and logon system - it is FAR too much work.
Ok, now that I outlined the above, we are of course still here to learn. So, lets fix up your code you have.
So, first up, I assume that you gone project->(your project properties), and under settings have setup a connection string (don't type those in manually - set that up in settings so you don't have to code out connection strings in code. You want ONE common connecting setting, since then you have one place to change this when you get around to publishing to a actual web site.
That setting is the ones you will find here:
Ok, now our code. Like everyone, it gets a bit tiring to wear out a few keyboards ever time we need to pull some data. And eventually, you want to consider a data framework like EF (entity framework) to class out and "abstract" your data base operations.
However, when starting out - I think it is GREAT idea to try + test and play with some basic and simple database operations - such as your example sql queries.
So, first up, lets build that save world poverty's and the keyboards (so we don't have to re-code over and over some simple SQL queries)
So, lets drop in this code:
DataTable LoadDataByQuery(SqlCommand cmdSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
cmdSQL.Connection = conn;
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
return rstData;
}
So, now your code can become this:
As pointed out we CAN NOT and NEVER just check password alone, since many people might have the same password.
So we can check for user - or give message
Or THEN check for user + password - and give bad password message.
Also, try to code without such a lot of nesting - its hard to debug and hard to follow. I tend to like reverse the conditions, and BAIL OUT of the code when things go wrong and then keep going if code is ok. That way you remove a boatload of nested if /else.
Try this code:
if (txtusername.Text == string.Empty)
{
msgtr.Visible = true;
lblMessage.Text = "Please enter a user name";
return;
}
// check/get user
SqlCommand sql = new SqlCommand();
sql.CommandText = #" select * from idpass where username = #user";
sql.Parameters.Add("#user", SqlDbType.NVarChar).Value = txtusername.Text;
DataTable dtForNameAndRole = LoadDataByQuery(sql);
if (dtForNameAndRole.Rows.Count == 0)
{
msgtr.Visible = true;
lblMessage.Text = "no such user";
return;
}
// if we get this far, then user name = ok
// user ok, try for pass word
sql.CommandText += " AND password = #Pass";
sql.Parameters.Add("#Pass", SqlDbType.NVarChar).Value = txtpassword.Text;
DataTable dtForNameAndRole2 = LoadDataByQuery(sql);
if (dtForNameAndRole2.Rows.Count == 0)
{
msgtr.Visible = true;
lblMessage.Text = "Sorry! Invalid user password";
lblMessage.ForeColor = Color.Red;
return;
}
//get this far, user + password = ok
Response.Redirect("Dashboard.aspx");
}
Note also how our human minds work. For example, we read this post on SO? you read from top to bottom - and your brain is thus wired to work this way.
As a result, note how easy the above code is not only to read, but follow.
Hum, check for user name? no good, setup message - exit - we are done!!
If user ok, hey, lets keep working our way though this problem - lets try user + password? no good, setup message - exit - we are done!
Hey, if we get this far? then we are done!!!
Give the above approach a try - I think you like this idea and style.
Note also, while we DID chew up about 2 extra lines of code to setup parameters?
Those parameters are sql injection safe. We were able to "additive" to the sql and the parameters (thus saving even more code).
We did not have to worry about single quotes - again string concatenations are error prone.
So my lesson and point? We used parameters NOT ONLY to prevent sql injection, but we in fact wound up with again more readable and maintainable code, and did not have to mess with string concatenate into the sql (well, ok, we did some concatenation - but NOT with a messy mix of single and double quotes). I point this out, since not only did we gain sql injection code, but the efforts to write the code was ALSO less. I never liked people just banging the drum to not use sql concatenate strings based on user input - but ALSO one should then at least provide a coding approach that reduces the pain and suffering for having suggested code to prevent sql injection.
I often use the above EVEN WHEN there is no chance of sql injection, since you can even on the fly add to the sql, and as above shows, on the fly even build up and add more parameters as we did above.
Good luck - all the best in the new year.
public DataSet Login()
{
names.Add("#ID"); types.Add(SqlDbType.VarChar); values.Add(RegistrationID);
names.Add("#Password"); types.Add(SqlDbType.VarChar); values.Add(password);
return DAobj.GetDataSet(SP_LoginAuthentication, values, names, types);
}
create proc SP_LoginAuthentication
#ID varchar(50),
#Password varchar(50)
as
begin
select * from TableName where id=#ID and Password=#Password And IsActive=1
end
``~
I am currently attempting to write a .net 4.6 console app to work with a database, below is the test database structure and I have tried a number of tutorials in order to set about the best way to insert and update the data and what i seem to come up with seems somewhat cumbersome or not particularly manageable.
USE [Test_Table]
GO
INSERT INTO [dbo].[Test_Data]
([Identifier]
,[XDocument]
,[XVersion]
,[XSubVersion]
,[SubmittedBy]
,[SubmissionID]
,[SubmissionDateTime]
,[AssociatedFiles]
,[UpdatedXdocument]
,[DateTimeUpdated]
,[UpdateComments])
VALUES
(<Identifier, nvarchar(20),>
,<XDocument, xml,>
,<XVersion, int,>
,<XSubVersion, int,>
,<SubmittedBy, nvarchar(20),>
,<SubmissionID, nvarchar(20),>
,<SubmissionDateTime, datetime,>
,<AssociatedFiles, nvarchar(max),>
,<UpdatedXdocument, xml,>
,<DateTimeUpdated, datetime,>
,<UpdateComments, nvarchar(10),>)
GO
At the moment i am looking at this tutorial: https://sqlchoice.azurewebsites.net/en-us/sql-server/developer-get-started/csharp/win/step/2.html
However i would really like to know what the best/most professional way in order to insert and update data against this? as it I will seed some columns but then update later on, to date i have not needed to use sql data as yet so would really like to start with a good footing from experienced programmers.
my connection method is this which works great:
SqlConnection _sqlConnection;
SqlDataReader _sqlData;
SqlCommand _sqlCommand;
public bool ConnectToDB()
{
try
{
string conString = $"Data Source={TEST_Config.Database_Host};Initial Catalog={TEST_Config.Database_Name};Integrated Security={TEST_Config.Integrated_Security}";
_sqlConnection = new SqlConnection(conString);
_sqlConnection.Open();
return true;
}
catch(Exception CTDB_EX)
{
log.Info($"Issues Encountered Connecting to the Database: {CTDB_EX.Message}");
if (log.IsDebugEnabled)
{
log.Debug($"STACK_TRACE: {CTDB_EX.StackTrace}");
}
return false;
}
}
After this i ran through a number of tutorials but struggled with larger column sets and handling them in the best way, I then decided to create a class for the columns with getters and setters ie
public string _Identifier {get;set;}
etc etc
but at this point i stalled and decided to look for advice.
Many thanks in advance.
Try to add a .dbml file in your project, using this you could manage all the database related activities with drag and drop database objects. It uses LINQ for all database transaction (select, insert, update, delete).
I am developing C# desktop appllication using MS SQL server database.
I Keep different class as follow connect to database.
using System.Data.Odbc;
class DataBaseConnection
{
private OdbcConnection conn1 = new OdbcConnection(#"FILEDSN=C:/OTPub/Ot.dsn;" + "Uid=sa;" + "Pwd=otdata#123;"); //"DSN=Ot_DataODBC;" + "Uid=sa;" + "Pwd=otdata#123;"
//insert,update,delete
public int SetData(string query)
{
try
{
conn1.Open();
OdbcCommand command = new OdbcCommand(query, conn1);
int rs = command.ExecuteNonQuery();
conn1.Close();
return rs;
}
catch (Exception ex)
{
conn1.Close();
throw ex;
}
}
//select
public System.Data.DataTable GetData(string sql)
{
try
{
conn1.Open();
OdbcDataAdapter adpt = new OdbcDataAdapter(sql, conn1);
DataTable dt = new DataTable();
adpt.Fill(dt);
conn1.Close();
return dt;
}
catch (Exception ex)
{
conn1.Close();
throw ex;
}
}
}
in my reqierd place i make object to that DatabaseConnection class and call to get and set method as requirment.
as an example ----
DataBaseConnection db = new DataBaseConnection();
string SaveNewEmp = "INSERT INTO Employee (Service_ID, Title, Name, Initials, ) VALUES ('" + servicenumber + "','" + title + "','" + fullname + "','" + initials + "')";
int returns = db.SetData(SaveNewEmp);
am i allow to SQl injection from this method?
how avoid sql injection without using stored procedure?
You avoid SQL Injection the same way as you would anywhere else - by keeping SQL code separate from data. You can't do that if you insist on having the interface be based on just passing in a string.
I'd get rid of your wrapper class (it's just obscuring things) and make use of Parameters to pass the data alongside your query.
(I'd also recommend that you just use using statements around the various database objects rather than your current manual efforts to ensure Close is called which is also slightly breaking good error handling by re-throwing exceptions)
(Also, I'd recommend using new OdbcConnection objects wherever you need them rather than trying to share a single one - you'll be thankful you've done this as soon as any notion of multi-threading enters your codebase, which is practically inevitable these days)
Most important technique is to used bind variables like this:
string SaveNewEmp =
"INSERT INTO Employee (Service_ID, Title, Name, Initials) VALUES (?, ?, ?, ?)";
command.Parameters.Add("#servicenumber", OdbcType.Int).Value = ...;
command.Parameters.Add("#title", OdbcType.VarChar).Value = ...;
command.Parameters.Add("#fullname ", OdbcType.VarChar).Value = ...;
command.Parameters.Add("#initials ", OdbcType.VarChar).Value = ...;
Usually this lead also into a performance gain and you don't have to take care about quoting, imagine the title would be It's your day - this would fail with your approach.
Update
Using a list of parameters is straight forward:
public int SetData(string query, OdbcParameterCollection parList)
{
...
OdbcCommand command = new OdbcCommand(query, conn1);
OdbcCommand.Parameters.Add(parList);
}
var parList = new OdbcParameterCollection();
parList.Add("#servicenumber", OdbcType.Int);
parList.Add("#title", OdbcType.VarChar);
...
int ret = SetData(query, parList);
However, I did not test it perhaps you have to run
foreach ( OdbcParameter aPar in parList ) {
OdbcCommand.Parameters.Add(aPar);
}
Using List<>
Damien_The_Unbeliever's answer is mostly good, but I would like to improve it/ version it.
You can also change the SetData and GetData methods and add them an array of parameters (although I do share his/her thoughts in getting rid of the class, you could make it abstract to make more specifica DAL classes).
The only requirement to avoid SQL Injection is using parameters, either using stored procedures (impossible due to question requirements) or queries written in your code.
There is a slight chance of getting into SQL Injection even if using parameters, if the SQL executed (in coded query or in the stored procedure) does use sp_execute_sql or similar. In case of using sp_execute_sql in your query, make sure to avoid writting it with user provided info. You can set parameters to the sp_execute_sql function as a second optional parameter.
This is a recurring (for the last 20 years at least) question, but I earnestly believe I have a new answer... use QueryFirst. You get the advantages of stored procedures, but your SQL lives in .sql files in your application, versioned with your app. You create parameters just by referencing them in your SQL. All the parameter handling code is generated for you. You (and your team) have to use parameters because there's no other way. The possibility of doing something unsafe is removed. And there are tons of other advantages: you edit your sql in a real environment, with syntax validation and intellisense. Your queries are continually integration tested against your db, and their wrapper code regenerated. All errors are trapped as you type, or when you save a .sql, or, last resort, when you build. In theory, there are no runtime errors from data access.
Usually rigour comes at the cost of simplicity/ease-of-dev. This approach is much more rigorous and much easier to use than the traditional sql-in-string-literals approach. Coming soon, language and platform portability. Drag and drop a sql query from C# project on windows into a Node express app on linux or mac, rebuild, and you get a typescript wrapper instead of a C# one. That should get folk's attention.
disclaimer: I wrote QueryFirst.
Download here.
Little blog here.
I have a customer provided database which is configured with multiple users. Each user has their own username/password etc, which are database logins for SQL Server.
In legacy software, the user is asked for their database and password which is then used to form a connectionstring in code.
I am tasked with replacing a lot of the database code for this, and I need a way of checking a username and password against the database quite quickly. At present, using Linq, if the password is incorrect I eventually get a System.Data.SqlClient.SqlException but this takes quite a while to actually throw (I assume a timeout?).
Does anybody know a good way that I can test my username/password combo against the database quickly?
You could try opening a connection through ADO, with a reduced timeout
SqlConnection conn = new SqlConnection (yourconnectionstring + ";Connection Timeout=1;");
try
{
conn.Open();
conn.Close();
}
catch (SqlException ex)
{
if (ex.Number == 18456)
{
// invalid login
}
}
18456 is SQL Invalid login
The default connection timeout is 15 seconds.
I would argue that you don't want the database (or anything, really) to be able to tell you that the credentials that you've passed in are incorrect. Why? Because that allows for brute force checking. Even introducing a small delay goes a long way in thwarting such attempts.
The Scenario:
I have a mobile phone comparing asp.net website which displays deals of various networks. The data about the deals we receive from the networks is in an excel sheet. We import the data from the excel sheets to the tables of each network in our database. Now, the data that we receive is not consistent for every network, as in, a network may name give the phone name as 'curve 8250' and another may give it as '8250 curve' and another might give it as '8250curve'.
Now, we have another module which allows the user to view the deals of a particular handset available on all the networks. To make this module work, what we need to do id make sure that the phone names are consistent for all the networks.
For this, I am planning to make a module for the webadmin which displays the phone names(probably in a gridview) from all the network tables, and the webmaster could edit the phone names so as to make them consistent. The retrieval of the distinct column names from all the tables was easy, and that is done.
The Problem:
Now, the real part is that how can we program the module so that it updates the particular column values in all the network tables. The schema of each table is exactly the same.
Edit: I always forget to add something :# . I know it can be done the hard way, in code behind, running a loop. But is there any simpler, hassle free way out there? like some datacontrol that would make life a bit easier in this situation?
Update:
I tried doing this using code behind. I made a gridview and displayed the data using item templates, and also provided a textbox in a second template. Then on a button click, I'm running this code:
protected void Button1_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection(ConfigurationSettings.AppSettings[0].ToString());
foreach(GridViewRow gvr in GridView1.Rows)
{
TextBox tb = (TextBox)gvr.FindControl("New Value");
Label lbl = (Label)gvr.FindControl("Old Value");
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
if (lbl.Text != tb.Text)
{
try //updation if primary key constraint is not broken
{
con.Open();
cmd.CommandText = myupdatecommand; /*this is not the actual command that I'm passing, the command I'm passing does contain the values lbl.Text & tb.Text. This is just to make it a better read.*/
cmd.ExecuteNonQuery();
}
catch (SqlException sqe)
{
if (sqe.ErrorCode == -2146232060)//if primary key constraint is broken
{
try
{
//delete the row from the table that contains only unique phone names
cmd.CommandText = deletecommand;
cmd.ExecuteNonQuery();
}
catch { }
}
}
finally
{
con.Close();
}
//Update table2
try //only updation as here the phone name is not a primary key
{
con.Open();
cmd.CommandText = updatetable2;
cmd.ExecuteNonQuery();
}
catch
{
}
finally
{
con.Close();
}
.
.
.
//similarily update rest of the tables
.
.
.
Response.Redirect(Request.Url.ToString());
}
}
When I run the this code, everything happens smoothly, but when we update more than one row in the grid at a time, the updation only occurs for the first edited row, the other edited rows are remaining the same.
I know it must be a very small thing that I'm missing out on here, but I'm not able to proceed further :(
Any help on the matter is highly appreciated. Thanks in advance!
PS- I'm using ASP.Net 3.5, with c# as code behind, and SQL Server 2005 as back-end.
OK, I'm going to assume you are using LINQ-to-Sql, but in theory, it shuoldn't matter, the basic principle is the same.
You will need a collection of connection string, one for each each database. Presumably you already have this.
using (TransactionScope scope = new TransactionScope())
{
foreach (var connStr in listOfConnStr)
{
using (var db = new MyDataContext(connStr);
{
// do update here.
}
}
}
That's pretty much it.
You could pass the "do update here" part in as a lambda function.
To be honest, I'm now embarrassed to answer my own question.
The problem was just that I had mistakenly put the Response.Redirect(Request.Url.ToString());
inside the if loop which itself is inside the foreach loop.
When will I stop doing silly mistakes :|