I am passing form values to stored procedure parameters and i have a problem...
I want to execute this stored procedure from a C# program.
I am VERY new at this, so any help on why I am getting these errors is greatly appreciated.
Stored Procedure Parameters
ALTER PROCEDURE [dbo].[User]
(
#pname varchar(100),
#Colour varchar(100),
#Sheet varchar(100),
#Size varchar(100),
#GSM varchar(100),
#pcost varchar(100),
#is_deleted bit,
#DOC datetime
)
as begin
INSERT INTO [SMjobcard].[dbo].[Papertype]
([pname]
,[Colour]
,[Sheet]
,[Size]
,[GSM]
,[pcost]
,[is_deleted]
,[DOC])
VALUES
(#pname,#Colour,#Sheet,#Size,#GSM,#pcost,#is_deleted,#DOC)
END
C#
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Data.OleDb;
public partial class Admin : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
String ConnString = ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
SqlConnection con = new SqlConnection(ConnString);
//SqlConnection con = new SqlConnection("Data Source=(local);Initial Catalog=SMjobcard;Integrated Security=True");
//con.Open();
SqlCommand cmd = new SqlCommand(ConnString);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "User";
cmd.Parameters.Add("#pname", SqlDbType.VarChar,50).Value = TextBox2.Text.Trim();
cmd.Parameters.Add("#Colour", SqlDbType.VarChar,50).Value = TextBox3.Text.Trim();
cmd.Parameters.Add("#Sheet", SqlDbType.VarChar,50).Value = TextBox4.Text.Trim();
cmd.Parameters.Add("#Size", SqlDbType.VarChar,50).Value = TextBox5.Text.Trim();
cmd.Parameters.Add("#GSM", SqlDbType.VarChar,50).Value = TextBox6.Text.Trim();
cmd.Parameters.Add("#pcost", SqlDbType.VarChar,50).Value = TextBox7.Text.Trim();
cmd.Parameters.Add("#is_deleted", SqlDbType.Bit).Value = true;
cmd.Parameters.Add("#DOC", SqlDbType.DateTime).Value = TextBox9.Text.Trim();
cmd.Connection = con;
try
{
con.Open();
cmd.ExecuteNonQuery();
lblmsg.Text = "Record inserted successfully";
}
catch (Exception ex)
{
ex.ToString();
}
finally
{
con.Close();
con.Dispose();
}
}
}
** i have an error for converting string to decimal,string to Boolean,string to decimal plz help me **
Please check your table design and then create the Stored Procedure.it may be possible that your are inserting wrong data to wrong column.means string data to bool column.so please check.
Related
I have a large number of stored procedures to work with and I have to work with Entity Framework.
I got for example this controller where I'm just calling the database to show my table:
public class CarguioController : Controller
{
public ActionResult Index(int? page)
{
string cs = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
using (SqlConnection conn = new SqlConnection(cs))
{
// establece conneciĆ³n
SqlParameter param1 = new SqlParameter();
param1.ParameterName = "#MODO";
param1.SqlDbType = SqlDbType.Int;
param1.Value = 2;
SqlCommand cmdProcedure = new SqlCommand(#"Almacen.[PRC_Carguio]", conn);
cmdProcedure.Parameters.Add(param1);
conn.Open();
cmdProcedure.CommandType = CommandType.StoredProcedure;
SqlDataReader dr = cmdProcedure.ExecuteReader();
List<CarguioViewModel> lst = new List<CarguioViewModel>();
int pageNumber = page ?? 1;
int pageSize = 8;
if (dr.HasRows)
{
while (dr.Read())
{
lst.Add(new CarguioViewModel
{
Carguio_ID = dr.GetInt32(0),
Vehiculos_ID = dr.GetInt32(1),
ManifiestoCarga_ID = dr.GetInt32(2),
Guia_ID = dr.GetInt32(3),
Programaciones_ID = dr.GetInt32(4),
Numero = dr.GetInt32(5),
NroMobil = dr.GetString(6),
Fecha = dr.GetDateTime(7),
Usuarios_ID = dr.GetInt32(8),
Sucursales_IS = dr.GetInt32(9)
});
//display retrieved record
}
return View(lst.ToPagedList(pageNumber, pageSize));
}
else
{
Console.WriteLine("No data found.");
}
dr.Close();
conn.Close();
}
return View();
}
}
As you can see, I have to connect with the SQL Server database many times. Maybe you have done a similar job with ASP.NET MVC projects or have any idea to refactor my code?
I have more than 30 tables and everyone has more a Crud and other functions.
I've been searching for this but there is just the same example.
string cs = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
You can get create in General Utility class to read the connection, so that It is stay in one place in the code and read connection value from the Genral Utility class wherever you need it.
void Main()
{
string cn = GeneralUtility.getConnectionString();
}
public class GeneralUtility
{
public static string getConnectionString()
{
string cs = "";
try
{
cs = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
}
catch (Exception ex)
{
throw new Exception("Connection String Error " + ex.Message.ToString());
}
return cs;
}
}
I added a new element called ADO.Net Entity Data Model, where I retrieve all my Stored Procedures, It is helpful
I added a new element called ADO.Net Entity Data Model
Well, now my code is shorter than before:
public ActionResult Index(int? page)
{
List<CarguioModel> lst = new List<CarguioModel>();
int pageNumber = page ?? 1;
int pageSize = 8;
using (MarviBKPEntities prcAlm = new MarviBKPEntities())
{
List<PRC_Carguio_Result> prc = prcAlm.PRC_Carguio(2, null, null, null, null, null, null, null, null, null, null).ToList();
return View(prc.ToPagedList(pageNumber, pageSize));
}
return View();
}
Whta do you think? Could it cause some bad performance?
I want to call a stored procedure using Serilog. I am aware that there is no such sink so I am creating a custom Sink. I have my logic to call the stored procedure inside the Emit method of the StoredProcedureSink that implements ILogEventSink. Now, this stored procedure returns a value. How can I get this value when I use Log.Information();
class StoredProcedureSink : ILogEventSink
{
private string _connectionString;
public StoredProcedureSink(string connectionString)
{
_connectionString = connectionString;
}
public void Emit(LogEvent logEvent)
{
var conn = new SqlConnection(_connectionString);
conn.Open();
SqlCommand cmd = new SqlCommand(logEvent.MessageTemplate.ToString().Substring(0, logEvent.MessageTemplate.ToString().IndexOf('{')), conn);
cmd.CommandType = CommandType.StoredProcedure;
var properties = logEvent.Properties.GetValueOrDefault("SqlParams");
var json = JObject.Parse(properties.ToString().Substring(properties.ToString().IndexOf('{') - 1));
foreach(var kvp in json)
{
cmd.Parameters.Add(new SqlParameter(kvp.Key, ((JValue)kvp.Value).Value));
}
cmd.ExecuteNonQuery();
//I would like to read the value returned by the stored proc.
}
}
//I have a wrapper DBLogger in which I configure the serilog. I have published DBLogger as a nuget package so I can use it in all my apps.
public class DBLogger()
{
public DBLogger()
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.StoredProcedureSink(
"connectionString")
.CreateLogger();
}
public void Information(string storedProcedureName, T parameters)
{
try
{
Log.Information(storedProcedureName, parameters);
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
}
}
}
public class Program
{
static void Main()
{
var logger = new DBLogger();
logger.Information("storedProcedureName", params); //need the Id returned by the stored proc here.
}
}
That's not likely to be workable in practice using the normal Serilog model.
The standard processing involves the LogEvent being captured on the main thread, then supplied to each sink in turn - usually asynchronously, and often buffered.
The other concern is that in general, a sink definitely will not be propagating exceptions to the caller either (there is Audit logging, but even that's not intended for this sort of communication).
It seems to me that the sort of auditing you're seeking to accomplish is some distance from Serilog's sweet spot (I may be wrong though - please add some more detail to your question if so).
If you absolutely must do this, you can add an Enricher when logging, which sequesters a callback Action into the LogEvent's Properties, and have that pass it back. Please think long and hard before actually doing that though!
I ended up creating a static variable of StoredProcedureSink class and assigning the return value to that variable. Not sure if this would be the best way to do it.
class StoredProcedureSink : ILogEventSink
{
private string _connectionString;
**public static int returnValue;**
public StoredProcedureSink(string connectionString)
{
_connectionString = connectionString;
}
public void Emit(LogEvent logEvent)
{
var outputParam = new SqlParameter()
{
Direction = ParameterDirection.Output
};
try
{
using (SqlConnection conn = new SqlConnection(_connectionString))
{
using (SqlCommand cmd = new SqlCommand(logEvent.MessageTemplate.ToString().Substring(0, logEvent.MessageTemplate.ToString().IndexOf('{')), conn))
{
conn.Open();
cmd.CommandType = CommandType.StoredProcedure;
var properties = logEvent.Properties.GetValueOrDefault("SqlParams");
var jsonProp = JObject.Parse(properties.ToString().Substring(properties.ToString().IndexOf('{') - 1).Replace(#"\",""));
var lastParam = jsonProp.Last;
foreach (var kvp in jsonProp)
{
if(kvp.Key == lastParam.Path)
{
outputParam.ParameterName = kvp.Key;
outputParam.SqlDbType = SqlDbType.Int;
cmd.Parameters.Add(outputParam);
break;
}
cmd.Parameters.Add(new SqlParameter(kvp.Key, ((JValue)kvp.Value).Value));
}
cmd.ExecuteNonQuery();
}
**returnValue = (int)outputParam.Value;**
}
}
catch(System.Exception e)
{
Debug.WriteLine(e.Message);
}
}
}
public class DBLogger : ILogger
{
public DBLogger()
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.StoredProcedureSink(
"connectionString")
.CreateLogger();
}
~DBLogger()
{
Log.CloseAndFlush();
}
public static IHost CreateHostBuilder(string[] args) =>
new HostBuilder()
.UseSerilog() // <- Add this line
.Build();
public int Information<T>(string storedProcedureName, T parameters)
{
try
{
Log.Information(storedProcedureName, parameters);
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
}
**return StoredProcedureSink.returnValue;**
}
}
I am using asp.net core application with abp(Asp.net BoilerPlate) framework. I want to use stored procedure to get the data and also to implement CRUD operations in this code first architecture. What will be best way to do so?
Thanks in advance
Here is an example that sends a parameter to a stored procedure to delete a user:
public async Task DeleteUser(EntityDto input)
{
await Context.Database.ExecuteSqlCommandAsync(
"EXEC DeleteUserById #id",
default(CancellationToken),
new SqlParameter("id", input.Id)
);
}
See: Using Stored Procedure, User Defined Function and Views in a Custom Repository with ASP.NET Boilerplate
Source code is published on Github: https://github.com/aspnetboilerplate/aspnetboilerplate-samples/tree/master/StoredProcedureDemo
Create your custom repository, so you can access the dbcontext object and execute sql query by using this context. I have created some helper methods in my custom repository, hope it can help you:
/// <summary>
/// Map data from datareader to list object
/// </summary>
private List<T> MapToList<T>(DbDataReader reader)
{
var result = new List<T>();
if (reader.HasRows)
{
var props = typeof(T).GetRuntimeProperties();
var colMapping = reader.GetColumnSchema().Where(x => props.Any(p => p.Name.Equals(x.ColumnName, StringComparison.OrdinalIgnoreCase))).ToDictionary(key => key.ColumnName.ToLower());
while (reader.Read())
{
var item = Activator.CreateInstance<T>();
foreach (var prop in props)
{
var propValue = reader.GetValue(colMapping[prop.Name.ToLower()].ColumnOrdinal.Value);
prop.SetValue(item, propValue == DBNull.Value ? null : propValue);
}
result.Add(item);
}
}
return result;
}
/// <summary>
/// Execute command return empty result
/// </summary>
public int ExecuteSqlCommand(string sqlCommand, Dictionary<string, object> #params)
{
List<SqlParameter> sqlParams = new List<SqlParameter>();
foreach (var item in #params)
{
if (item.Value != null)
sqlParams.Add(new SqlParameter(item.Key, item.Value));
else
sqlParams.Add(new SqlParameter(item.Key, DBNull.Value));
}
if (#params.Count > 0)
sqlCommand += " ";
sqlCommand += String.Join(",", #params.Select(p => p.Key));
return Context.Database.ExecuteSqlCommand(sqlCommand, sqlParams.ToArray());
}
/// <summary>
/// Execute stored procedure return set of rows
/// </summary>
public IEnumerable<TResult> ExecuteStoredProcedureWithRowsResult<TResult>(string name, Dictionary<string, object> #params) where TResult : class
{
//Fix exception: ExecuteReader requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.
UnitOfWorkManager.Current.Options.IsTransactional = false;
using (var command = Context.Database.GetDbConnection().CreateCommand())
{
var result = new List<TResult>();
string sqlCmd = String.Format("{0} ", name);
if (command.Connection.State != System.Data.ConnectionState.Open)
command.Connection.Open();
try
{
foreach (var item in #params)
{
if (item.Value != null)
command.Parameters.Add(new SqlParameter(item.Key, item.Value));
else
command.Parameters.Add(new SqlParameter(item.Key, DBNull.Value));
command.CommandText = sqlCmd;
command.CommandType = System.Data.CommandType.StoredProcedure;
using (var reader = command.ExecuteReader())
{
result = MapToList<TResult>(reader);
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
command.Connection.Close();
}
return result;
}
}
And in application service, inject your custom repository, and can call stored procedure like:
var #params = new Dictionary<string, object>();
#params.Add("Id", 1);
var result = _customRepository.ExecuteStoredProcedureWithRowsResult<UserResult>("sp_getUsers", #params);
If you dont want to use EF, you can use Dapper, it is easy to use: http://www.c-sharpcorner.com/article/asp-net-core-web-api-with-dapper-and-vs-2017/
I have a form in my MVC 5 Webb App, a very simple form for "contact us":
-Name
-Email
-Subject
-Message (body)
I have to check the strings that the user input.
How can I check it in .NET ?
Update:
As Darin suggested, a Parameterizing Queries will take care of that, but I have a problem with implementation it with my architecture design of my web application:
I have a Ado Helper Class:
public class AdoHelper
{
static string connectionString = ConfigurationManager.ConnectionStrings["SQL_DB"].ConnectionString;
public static DataTable ExecuteDataTable(string query)
{
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
SqlCommand command = new SqlCommand(query, con);
SqlDataAdapter tableAdapter = new SqlDataAdapter(command);
DataTable dt = new DataTable();
tableAdapter.Fill(dt);
return dt;
}
}
public static void ExecuteNonQuery(string query)
{
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
SqlCommand command = new SqlCommand(query, con);
command.ExecuteNonQuery();
}
}
public static object ExecuteScalar(string query)
{
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
SqlCommand command = new SqlCommand(query, con);
return command.ExecuteScalar();
}
}
}
And I have Data Queries Class: ( I display here only the relevant function to this question)
public class DataQueries
{
public static void InsertContactForm(ContactForm form)
{
try
{
string query = "INSERT INTO ContactForm (Name, Email, Subject, Message, Reply) VALUES ( '" + form.Name + "','" + form.Email + "','" + form.Subject + "','" + form.Message + "','" + form.Reply + "')";
AdoHelper.ExecuteNonQuery(query);
}
catch (Exception ex)
{
throw ex;
}
}
}
When I want to insert data to my DB I call to a Data Queries function that communicate with the Ado Helper Class.
So the query pass to Ado Helper function as string well formed and ready to go, this creates a problem because I cant use parameters in the Ado Helper class (where I have SQL command instance).
Are there any workaround to this problem ?
Thanks.
Looks like your AdoHelper class is currently vulnerable to SQL injection. In order to avoid that you need to use parametrized queries. So I would start by refactoring this AdoHelper class so that it suits better those needs:
public class AdoHelper
{
private static string connectionString = ConfigurationManager.ConnectionStrings["SQL_DB"].ConnectionString;
public static int ExecuteNonQuery(string query, IDictionary<string, object> parameters)
{
using (var con = new SqlConnection(connectionString))
using (var command = con.CreateCommand())
{
con.Open();
command.CommandText = query;
foreach (var p in parameters)
{
command.Parameters.AddWithValue(p.Key, p.Value);
}
return command.ExecuteNonQuery();
}
}
}
and then you could call this method in order to perform the INSERT statement:
AdoHelper.ExecuteNonQuery(
"INSERT INTO ContactForm (Name, Email, Subject, Message, Reply) VALUES (#Name, #Email, #Subject, #Message, #Reply)",
new Dictionary<string, object>
{
{ "#Name", "form.Name" },
{ "#Email", "form.Email" },
{ "#Subject", "form.Subject" },
{ "#Message", "form.Message" },
{ "#Reply", "form.Reply" }
}
);
What you need is parametrized queries. In the cmd object in ADO.NET, for example, there is a straight forward to do that:
using (var cmd = new SqlCommand())
{
// Add the input parameter and set its properties.
using (var parameter = new SqlParameter())
{
parameter.ParameterName = "#CategoryName";
parameter.SqlDbType = SqlDbType.NVarChar;
parameter.Direction = ParameterDirection.Input;
parameter.Value = categoryName;
// Add the parameter to the Parameters collection.
cmd.Parameters.Add(parameter);
// Now you can execute query
}
}
http://msdn.microsoft.com/en-us/library/yy6y35y8%28v=vs.110%29.aspx
I have a table called Links.
two stored Procedures called sp_InsertLinks, sp_GetLinks.
I have simple webpart which takes two parameters and adds it the SQL Table call Links.
In The first Interface it displays the list of values from the database and a Button to ADD List.
When I click on the Link it displays next interface, where I can add txtbox for Link Name and Txtbox for Link URL.
And When I submit this The page is loading in the sequence of events of normal sharepoint lifecycle.
And I am unable to add the new links into the page because the button click method never gets fired.
Could any one have a look at this please?
The Code is :
using System;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;
using System.Text ;
using System.Data ;
using System.Data.SqlClient;
using System.Drawing;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
namespace ContextMenuOptionsUsingJQuery
{
[Guid("7a3a52d4-9ad6-44b2-b96f-852da1a95371")]
public class ContextMenuOptionsUsingJQuery : System.Web.UI.WebControls.WebParts.WebPart
{
SqlConnection con;
SqlCommand cmd;
SqlDataReader dr;
string Con_string = string.Empty;
Button btnAddLink;
Button btnAddNewLink;
StringBuilder outputDisplay;
TextBox txtLink;
TextBox txtLinkUrl;
Label lblDisplay = new Label();
public ContextMenuOptionsUsingJQuery()
{
}
protected override void CreateChildControls()
{
try
{
// Getting the Connection
ConnectionMethod();
// Calling the Appropraite Method or stored Procedures
RefreshData();
// Adding a New Link though the button
btnAddLink = new Button();
btnAddLink.Text = "Add Link";
btnAddLink.Click += new EventHandler(btn_AddLink);
//New item
Controls.Add(btnAddLink);
}
catch (Exception e)
{
Label l = new Label();
l.Text = e.StackTrace;
Controls.Add(l);
}
}
// Button Add Link
private void btn_AddLink(Object sender, EventArgs e)
{
Controls.Clear();
btnAddNewLink = new Button();
txtLink = new TextBox();
txtLinkUrl = new TextBox();
Controls.Add(txtLink);
Controls.Add(txtLinkUrl);
btnAddNewLink.Text = "ADD NEW Link";
btnAddNewLink.Click += new EventHandler(btnAddNewLink_Click);
Controls.Add(btnAddNewLink);
}
private void btnAddNewLink_Click(Object sender, EventArgs e)
{
int i;
try
{
ConnectionMethod();
cmd.CommandText = "sp_InsertLinks";
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter paramLinkName = new SqlParameter("#LinkName", SqlDbType.VarChar, 50);
SqlParameter paramLinkUrl = new SqlParameter("#LinkUrl", SqlDbType.VarChar, 50);
paramLinkName.Direction = ParameterDirection.Input;
paramLinkUrl.Direction = ParameterDirection.Input;
paramLinkName.Value = txtLink.Text.ToString();
paramLinkUrl.Value = txtLinkUrl.Text.ToString();
cmd.Parameters.Add(paramLinkUrl);
cmd.Parameters.Add(paramLinkName);
i = cmd.ExecuteNonQuery();
con.Close();
ConnectionMethod();
RefreshData();
}
catch (Exception exp)
{
Label l = new Label();
l.Text = exp.StackTrace;
Controls.Add(l);
}
finally
{
con.Close();
}
}
private void RefreshData()
{
cmd.CommandText = "sp_GetLinks";
cmd.CommandType = CommandType.StoredProcedure;
dr = cmd.ExecuteReader();
outputDisplay = new System.Text.StringBuilder();
outputDisplay.AppendLine("<br/>");
// Fetching the Data from the Datareader object
while (dr.Read())
{
outputDisplay.AppendLine("" + dr[1] + "" + "<br/><br/>");
}
con.Close();
outputDisplay.AppendLine("<br/> <br/>");
lblDisplay.Text = outputDisplay.ToString();
Controls.Add(lblDisplay);
}
// Method to get the Connection
public void ConnectionMethod()
{
con = new SqlConnection();
cmd = new SqlCommand();
Con_string = "Data Source=servername;Initial Catalog=HariVMTest;Integrated Security=True";
con.ConnectionString = Con_string;
con.Open();
cmd.Connection = con;
}
}
}
Thank you
Hari
I would nearly always recommend creating all your controls in CreateChildControls()
Then you should use the Visible property to show and hide the controls as needed.
The code would then look something like this:
public class ContextMenuOptionsUsingJQuery : System.Web.UI.WebControls.WebParts.WebPart {
Button btnAddLink;
Button btnAddNewLink;
protected override void CreateChildControls() {
btnAddLink = new Button();
btnAddLink.Text = "Add Link";
btnAddLink.Click += new EventHandler(btn_AddLink);
Controls.Add(btnAddLink);
btnAddNewLink.Text = "ADD NEW Link";
btnAddNewLink.Click += new EventHandler(btnAddNewLink_Click);
btnAddNewLink.Visible = false;
Controls.Add(btnAddNewLink);
}
private void btn_AddLink(Object sender, EventArgs e) {
btnAddLink.Visible = false;
}
private void btnAddNewLink_Click(Object sender, EventArgs e) {
}
}
If you do it this way, your events will more often than not, fire correctly.
i think you need to just add :
// Adding a New Link though the button
btnAddLink = new Button();
btnAddLink.Text = "Add Link";
btnAddLink.Click += new EventHandler(btn_AddLink);
before connectionmethod in createchildcontrol()
hope this works.