I'm currently working on application where one of the requirements is the ability to create SP, Tables, Functions, Triggers, etc. from inside ASP.NET. The language I'm using is C# but I don't know if this is even possible. Would you mind pointing me to the right direction or provide me with some code examples?
I tried looking online but I'm unable to find any information regarding this.
#rmayer06, I followed your advice and below is my code:
protected void createproc_Click(object sender, EventArgs e)
{
string sqlscript = File.ReadAllText(Server.MapPath("~/sp_create.sql"));
try
{
SqlConnection con = new SqlConnection();
SqlCommand cmd = new SqlCommand(sqlscript, con);
cmd.CommandType = CommandType.Text;
con.ConnectionString = ConfigurationManager.ConnectionStrings["TCKT"].ConnectionString;
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
catch (Exception ex)
{
throw new Exception("An error has occurred" + ex);
}
}
It may be possible using SqlCommand.ExecuteNonQuery(), or by using the classes in Microsoft.SqlServer namespace. I found this in a quick search: http://forums.asp.net/t/1703608.aspx/1
However, I would ask for additional clarification on your requirements if I were you. It seems odd that you would need to create SPs dynamically; generally, it is better to design them as part of the database if they are needed, as SPs will need to be optimized, debugged, etc.
On a related note, I have run database update scripts from within c#, which did create stored procedures as part of updating the database code. If that is what you are doing, I recommend the following:
Script your entire database to a single .SQL file.
Use the sqlcmd utility to execute the file against your local server. This can be done by calling System.Diagnostics.Process.Start() from the web application and supplying the necessary command-line parameters.
As a caveat, your web app process will need permissions to launch the sqlcmd process. Or as an alternative, you can use the SqlCommand class and just dump the entire contents of your SQL script into a string, which you pass to the command. I think I've done that too, and it worked.
Related
I am using visual studio Windows forms for a login/sign-up project. So how would I go about connecting my Microsoft access data base to my visual studio project and establishing a connection in the code so I can write out a command.
It uses a connection string similar to SQL.
public string ConnString => $"Provider=Microsoft.ACE.OLEDB.16.0;Data Source = {FilePathHere};"
To persist to the file using ADO.NET, it will look like
private void ExecuteWrite(string sql)
{
try
{
using (OleDbConnection conn = new OleDbConnection(ConnString))
{
OleDbCommand cmd = new OleDbCommand(sql, conn) { CommandType = CommandType.Text };
conn.Open();
_ = cmd.ExecuteNonQuery();
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
Console.WriteLine(e.ToString());
}
}
A couple notes on Access:
Access has its own form of SQL which is very different than what you are used to, for example instead of char varchar you will have types like text. Check the full list of differences here
the SQL string you write must use " to escape things such as problematic column names
Tables cannot exceed 255 columns for some reason. Be ready to create seperate queries to split any massive table that goes over that limit, as Access will straight up refuse to process that query. Its the only db I know that suffers from such a limitation and it was a pain for a project I worked on. I got around it using some LINQ to split up the desired columns, and then crafting the separate CREATE or INSERT queries
I am trying to setup my .NET 4.7.1 program that is connecting to a MySQL database 8.0 to use the minimum privileges to run.
The .NET program is using MySql.Data to make connection. The minimum right for a user to execute a stored procedure is typically only EXECUTE privilege. This works fine from MySQL workbench or command line.
Upon running the .NET program this does return the following exception:
System.Data.SqlTypes.SqlNullValueException: 'Data is Null. This method or property cannot be called on Null values.'
To make it easy, I have create a very small demo program to demonstrate the issue.
Setup of the database:
CREATE DATABASE Spike;
CREATE PROCEDURE TestAccess()
BEGIN
END;
CREATE USER Spike#localhost IDENTIFIED WITH mysql_native_password BY 'sample';
GRANT EXECUTE ON PROCEDURE `TestAccess` TO Spike#localhost;
Setup program code:
static void Main(string[] args)
{
using (MySqlConnection conn = new MySqlConnection("Server=localhost;Database=Spike;uid=Spike;pwd=sample"))
{
conn.Open();
Console.WriteLine("Connection open");
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = conn;
cmd.CommandText = "TestAccess";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
Console.WriteLine("Query executed");
}
Console.ReadKey();
}
The crash happens at the line cmd.ExecuteNonQuery();
The stack from the crash is interesting, since it seems to indicate that the information_schema is queried. When logging all statements I can see that the last statement before the exception is:
SELECT * FROM information_schema.routines WHERE 1=1 AND routine_schema LIKE 'Spike' AND routine_name LIKE 'TestAccess'
I cannot grant different rights on information_schema, but I could give more rights on the stored procedure to make more information visible in the routines table, this feels wrong however. Simple tests with granting CREATE and ALTER access also did not work.
Is there something else I can do, without granting too much privileges?
This appears to be a bug in Connector/NET, similar to bug 75301 but a little different. When it's trying to determine parameter metadata for the procedure, it first creates a MySqlSchemaCollection named Procedures with all metadata about the procedure. (This is the SELECT * FROM information_schema.routines WHERE 1=1 AND routine_schema LIKE 'Spike' AND routine_name LIKE 'TestAccess' query you see in your log.)
The Spike user account doesn't have permission to read the ROUTINE_DEFINITION column, so it is NULL. Connector/NET expects this field to be non-NULL and throws a SqlNullValueException exception trying to read it.
There are two workarounds:
1) The first, which you've discovered, is to set CheckParameters=False in your connection string. This will disable retrieval of stored procedure metadata (avoiding the crash), but may lead to harder-to-debug problems calling other stored procedures if you don't get the order and type of parameters exactly right. (Connector/NET can no longer map them for you using the metadata.)
2) Switch to a different ADO.NET MySQL library that doesn't have this bug: MySqlConnector on NuGet. It's highly compatible with Connector/NET, performs faster, and fixes a lot of known issues.
I found an answer with which I am quite pleased. It is changing the connection string by adding CheckParameters=false:
using (MySqlConnection conn = new MySqlConnection("Server=localhost;Database=Spike;uid=Spike;pwd=sample;CheckParameters=false"))
This disables parameter checking, and thereby information_schema queries.
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'm developing a simple C# Windows Forms Applicaiton. Can someone provide me with examples of how to:
Open connection to AS400 system
Use a string to query the opened connection.
Store query results in some manner.
Use the stored results as DataSource for a ListView Control
I don't have a preference 1 way or the other (nor know the difference) between ODBC and ADO methods for accomplishing this, but my current efforts are failing sharply. For anyone interested, Here is my current code which seems to be missing an important step somewhere, hence why I'm seeking examples.
Any help greatly appreciated!
EDIT:
Figured it out:
string connString = "DRIVER=Client Access ODBC Driver (32-bit); SYSTEM=XX.XX.X.XX; UID=XXXX; PWD=XXXX";
OdbcConnection conn = new OdbcConnection();
conn.ConnectionString = connString;
OdbcCommand cmd = new OdbcCommand(query, conn);
conn.Open();
OdbcDataReader dr = cmd.ExecuteReader();
if (!dr.HasRows)
{
throw new Exception("No records found.");
}
Int16 x = 0;
while (dr.Read())
{
....
}
Please go through the links in the post
http://social.msdn.microsoft.com/Forums/en-US/7292a82f-e4f7-4849-aaef-2e16cee159c8/how-to-access-as400-system-from-c-net-2008
With C#, I would think you would want to use the .NET Data Provider in IBM i Access for Windows, to provide the highest level of functionality to your C# program. But of course you can use ADO or ODBC directly if you so choose.
In any event, you should probably pay attention to the options available in the connection settings. Your system administrator may have specific advice, but it generally better practice to use system naming, to use the flexibility of library lists (a schema search path). If they are current on OS updates for v7.1, then system naming does not require adopting '/' syntax.
Basically, I would like a brief explanation of how I can access a SQL database in C# code. I gather that a connection and a command is required, but what's going on? I guess what I'm asking is for someone to de-mystify the process a bit. Thanks.
For clarity, in my case I'm doing web apps, e-commerce stuff. It's all ASP.NET, C#, and SQL databases.
I'm going to go ahead and close this thread. It's a little to general and I am going to post some more pointed and tutorial-esque questions and answers on the subject.
MSDN has a pretty good writeup here:
http://msdn.microsoft.com/en-us/library/s7ee2dwt(VS.71).aspx
You should take a look at the data-reader for simple select-statements. Sample from the MSDN page:
private static void ReadOrderData(string connectionString)
{
string queryString =
"SELECT OrderID, CustomerID FROM dbo.Orders;";
using (SqlConnection connection = new SqlConnection(
connectionString))
{
SqlCommand command = new SqlCommand(
queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
try
{
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}",
reader[0], reader[1]));
}
}
finally
{
// Always call Close when done reading.
reader.Close();
}
}
}
It basicly first creates a SqlConnection object and then creates the SqlCommand-object that holds the actual select you are going to do, and a reference to the connection we just created. Then it opens the connection and on the next line, executes your statements and returns a SqlDataReader object.
In the while-loop it then outputs the values from the first row in the reader. Every time "reader.Read()" is called the reader will contain a new row.
Then the reader is then closed, and because we are exiting the "using"-secret, the connection is also closed.
EDIT: If you are looking for info on selecting/updating data in ASP.NET, 4GuysFromRolla has a very nice Multipart Series on ASP.NET 2.0's Data Source Controls
EDIT2: As others have pointed out, if you are using a newer version of .NET i would recommend looking into LINQ. An introduction, samples and writeup can be found on this MSDN page.
The old ADO.Net (sqlConnection, etc.) is a dinosaur with the advent of LINQ. LINQ requires .Net 3.5, but is backwards compatible with all .Net 2.0+ and Visual Studio 2005, etc.
To start with linq is ridiculously easy.
Add a new item to your project, a linq-to-sql file, this will be placed in your App_Code folder (for this example, we'll call it example.dbml)
from your server explorer, drag a table from your database into the dbml (the table will be named items in this example)
save the dbml file
You now have built a few classes. You built the exampleDataContext class, which is your linq initializer, and you built the item class which is a class for objects in the items table. This is all done automatically and you don't need to worry about it. Now say I want to get record with the itemID of 3, this is all I need to do:
exampleDataContext db = new exampleDataContext(); // initializes your linq-to-sql
item item_I_want = (from i in db.items where i.itemID == 3 select i).First(); // using the 'item' class your dbml made
And that's all it takes. Now you have a new item named item_I_want... now, if you want some information from the item you just call it like this:
int intID = item_I_want.itemID;
string itemName = item_I_want.name;
Linq is very simple to use! And this is just the tip of the iceberg.
No need to learn antiquated ADO when you have a more powerful, easier tool at your disposal :)
Reads like a beginner question. That calls for beginner video demos.
http://www.asp.net/learn/data-videos/
They are ASP.NET focused, but pay attention to the database aspects.
topics to look at:
ADO.NET basics
LINQ to SQL
Managed database providers
If it is a web application here are some good resources for getting started with data access in .NET:
http://weblogs.asp.net/scottgu/archive/2007/04/14/working-with-data-in-asp-net-2-0.aspx
To connect/perform operations on an SQL server db:
using System.Data;
using System.Data.SqlClient;
string connString = "Data Source=...";
SqlConnection conn = new SqlConnection(connString); // you can also use ConnectionStringBuilder
connection.Open();
string sql = "..."; // your SQL query
SqlCommand command = new SqlCommand(sql, conn);
// if you're interested in reading from a database use one of the following methods
// method 1
SqlDataReader reader = command.ExecuteReader();
while (reader.Read()) {
object someValue = reader.GetValue(0); // GetValue takes one parameter -- the column index
}
// make sure you close the reader when you're done
reader.Close();
// method 2
DataTable table;
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(table);
// then work with the table as you would normally
// when you're done
connection.Close();
Most other database servers like MySQL and PostgreSQL have similar interfaces for connection and manipulation.
If what you are looking for is an easy to follow tutorial, then you should head over to the www.ASP.net website.
Here is a link to the starter video page: http://www.asp.net/learn/videos/video-49.aspx
Here is the video if you want to download it: video download
and here is a link to the C# project from the video: download project
Good luck.
I would also recommend using DataSets. They are really easy to use, just few mouse clicks, without writing any code and good enough for small apps.
If you have Visual Studio 2008 I would recommend skipping ADO.NET and leaping right in to LINQ to SQL
#J D OConal is basically right, but you need to make sure that you dispose of your connections:
string connString = "Data Source=...";
string sql = "..."; // your SQL query
//this using block
using( SqlConnection conn = new SqlConnection(connString) )
using( SqlCommand command = new SqlCommand(sql, conn) )
{
connection.Open();
// if you're interested in reading from a database use one of the following methods
// method 1
SqlDataReader reader = command.ExecuteReader();
while (reader.Read()) {
object someValue = reader.GetValue(0); // GetValue takes one parameter -- the column index
}
// make sure you close the reader when you're done
reader.Close();
// method 2
DataTable table;
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(table);
// then work with the table as you would normally
// when you're done
connection.Close();
}