C# sql wcf parametres exception - c#

This is probably my first C# program, so i kindly ask for you patience.
Im trying to create an app that adds/deletes/updates student data from a local MS Sql database by following an online tutorial.
Database- local windows authentication called with table Registration:
primary key- UserId int
UserName varchar (100)
Password varchar (20)
Country varchar (100)
email varchar (20)
The program uses a WCF service and it starts correctly, however i keep getting the error when i try to invoke the InsertUserDetails().
Error text:
The parameterized query '(#UserID int,#UserName nvarchar(4000),#Password nvarchar(4000),#' expects the parameter '#UserName', which was not supplied.
C# code for Service1.cs:
public class Service1 : IService1
{
public DataSet SelectUserDetails()
{
SqlConnection con = new SqlConnection(#"Server=Robert;Database=Trying;Trusted_Connection=True;");
con.Open();
SqlCommand cmd = new SqlCommand("Select * from Registration", con);
SqlDataAdapter sda = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
sda.Fill(ds);
cmd.ExecuteNonQuery();
con.Close();
return ds;
}
public void UpdateRegistrationTable(UserDetails userInfo)
{
SqlConnection con = new SqlConnection(#"Server=Robert;Database=Trying;Trusted_Connection=True;");
con.Open();
SqlCommand cmd = new SqlCommand("update Registration set UserName=#UserName,Password=#Password,Country=#Country, Email=#Email where UserID=#UserID", con);
cmd.Parameters.AddWithValue("#UserName", userInfo.UserName);
cmd.Parameters.AddWithValue("#Password", userInfo.Password);
cmd.Parameters.AddWithValue("#Country", userInfo.Country);
cmd.Parameters.AddWithValue("#Email", userInfo.Email);
cmd.ExecuteNonQuery();
con.Close();
}
public bool DeleteUserDetails(UserDetails userInfo)
{
SqlConnection con = new SqlConnection(#"Server=Robert;Database=Trying;Trusted_Connection=True;");
con.Open();
SqlCommand cmd = new SqlCommand("delete from Registration where UserID=#UserID", con);
cmd.Parameters.AddWithValue("#UserID", userInfo.UserID);
cmd.ExecuteNonQuery();
con.Close();
return true;
}
public string InsertUserDetails(UserDetails userInfo)
{
string Message;
SqlConnection con = new SqlConnection(#"Server=Robert;Database=Trying;Trusted_Connection=True;");
con.Open();
SqlCommand cmd = new SqlCommand("insert into Registration(UserID,UserName,Password,Country,Email) values(#UserID,#UserName,#Password,#Country,#Email)", con);
cmd.Parameters.AddWithValue("#UserID", userInfo.UserID);
cmd.Parameters.AddWithValue("#UserName", userInfo.UserName);
cmd.Parameters.AddWithValue("#Password", userInfo.Password);
cmd.Parameters.AddWithValue("#Country", userInfo.Country);
cmd.Parameters.AddWithValue("#Email", userInfo.Email);
int result = cmd.ExecuteNonQuery();
if (result == 1)
{
Message = userInfo.UserName + " Details inserted successfully";
}
else
{
Message = userInfo.UserName + " Details not inserted successfully";
}
con.Close();
return Message;
}
}
}
C# code for IService1.cs
[ServiceContract]
public interface IService1
{
[OperationContract]
string InsertUserDetails(UserDetails userInfo);
[OperationContract]
DataSet SelectUserDetails();
[OperationContract]
bool DeleteUserDetails(UserDetails userInfo);
[OperationContract]
void UpdateRegistrationTable(UserDetails userInfo);
}
// Use a data contract as illustrated in the sample below to add composite types to service operations.
[DataContract]
public class UserDetails
{
int userid;
string username;
string password;
string country;
string email;
[DataMember]
public int UserID
{
get { return userid; }
set { userid = value; }
}
[DataMember]
public string UserName
{
get { return username; }
set { username = value; }
}
[DataMember]
public string Password
{
get { return password; }
set { password = value; }
}
[DataMember]
public string Country
{
get { return country; }
set { country = value; }
}
[DataMember]
public string Email
{
get { return email; }
set { email = value; }
}
}
}

That means that the UserName Property of your UserDetails class seems to be null. Check if it has a value.
One way to mitigate such errors is to check the validity of the UserDetails instance in advance by specifiying the contract of your insert method.
public string InsertUserDetails(UserDetails userInfo)
{
if(null==userInfo)
throw new Exception("userInfo is null");
if(String.IsNullOrEmpty(userInfo.UserName))
throw new Exception("UserName is null or empty");
// and only after this check succeeds do the insert
}
If you want to allow null values you would have to translate the .NET NULL to the ado.NET DBNull.Value.
cmd.Parameters.AddWithValue("#UserName", userInfo.UserName ?? DBNull.Value);
Another possible solution would be to wrap your SQL in procedures and make the parameter nullable by providing a default parameter.
create procedure usp_InserProc #UserName varchar(32) = NULL
begin
... sql code
end

Related

C# Web API Parameter Always Returns All Values Instead of One

I am working on a Web API in C# and am getting my data from a SQL Database. The Get method returns all rows of (student) data, however even when I put a single student number in the GET call, it still returns all rows of data instead of a single row for the specified student. In my Roles Class I have;
public class Roles
{
List<Roles> studentRoles = new List<Roles>();
public string UserName { get; set; }
public string PersonName { get; set; }
public string Profile { get; set; }
public string Level { get; set; }
public int Year { get; set; }
public string Department { get; set; }
}
public class readRoles : Roles
{
public readRoles(DataRow dataRow)
{
UserName = (string)dataRow["UserName"];
PersonName = (string)dataRow["PersonName"];
Profile = (string)dataRow["Profile"];
Level = (string)dataRow["Level"];
Year = Convert.ToInt32(dataRow["Year"]);
Department = (dataRow["Department"] == DBNull.Value) ? "No Department" : dataRow["Department"].ToString();
}
public string UserName { get; set; }
public string PersonName { get; set; }
public string Profile { get; set; }
public string Level { get; set; }
public int Year { get; set; }
public string Department { get; set; }
}
In my Controller I have this;
List<Roles> studentRoles = new List<Roles>();
private SqlDataAdapter _adapter;
public IEnumerable<Roles> Get()
{
//Create link to database
string connString;
SqlConnection con;
connString = #"XXX";
DataTable _dt = new DataTable();
con = new SqlConnection(connString);
con.Open();
var sql = "some sql here";
SqlCommand CMD = new SqlCommand();
CMD.Connection = con;
CMD.CommandText = sql;
CMD.CommandType = System.Data.CommandType.Text;
SqlDataReader dr = CMD.ExecuteReader();
_adapter = new SqlDataAdapter
{
SelectCommand = new SqlCommand(sql, con)
};
_adapter.Fill(_dt);
List<Roles> roles = new List<Roles>(_dt.Rows.Count);
if (_dt.Rows.Count > 0)
{
foreach (DataRow studentrole in _dt.Rows)
{
roles.Add(new readRoles(studentrole));
}
}
return roles;
}
The above returns all the data as it should. To return a single row of data, I have the below Method but it still returns every single row instead of the row for the specified one when I do e.g. https://localhost:XXXXX/custom-roles-api/campusCustomRoles/12345;
[HttpGet]
public IHttpActionResult Get(string userName)
{
string connString;
SqlConnection con;
connString = #"XXX";
DataTable _dt = new DataTable();
con = new SqlConnection(connString);
con.Open();
var sql = "select distinct .... where student_reference = " + userName +;
SqlCommand CMD = new SqlCommand();
CMD.Connection = con;
CMD.CommandText = sql;
CMD.CommandType = System.Data.CommandType.Text;
SqlDataReader dr = CMD.ExecuteReader();
_adapter = new SqlDataAdapter
{
SelectCommand = new SqlCommand(sql, con)
};
_adapter.Fill(_dt);
List<Roles> roles = new List<Roles>(_dt.Rows.Count);
if (_dt.Rows.Count > 0)
{
foreach (DataRow studentrole in _dt.Rows)
{
roles.Add(new readRoles(studentrole));
}
}
var singlestu = roles.FirstOrDefault(e => e.UserName == userName);
return Ok(singlestu)
;
}
In the above example, I expect only data for student 12345 to be returned, but alas, all records are retrieved. In my WebConfig file, I have a custom Route like so;
public static void Register(HttpConfiguration config)
{
// Web API routes
// This is the original Route
//config.MapHttpAttributeRoutes();
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{Controller}/{id}",
// //routeTemplate: "api/{controller}/{action}/{id}",
// defaults: new { id = RouteParameter.Optional }
//);
// Custom Route
config.MapHttpAttributeRoutes();
// Define route
System.Web.Http.Routing.IHttpRoute rolesRoute = config.Routes.CreateRoute("custom-roles-api/{controller}/{id}",
new { id = RouteParameter.Optional }, null);
// Add route
config.Routes.Add("DefaultApi", rolesRoute);
}
Not sure where I have gone wrong and would be grateful for any pointers.
Many thanks in advance.
EDIT: As requested, please see below code when I used parameters;
[HttpGet]
public IHttpActionResult Get(string userName)
{
string connString;
SqlConnection con;
connString = #"XXXX";
DataTable _dt = new DataTable();
con = new SqlConnection(connString);
con.Open();
var sql = "select distinct .... where student_reference =#UserName " +
"and department ='LAW' " +;
SqlParameter param = new SqlParameter();
param.ParameterName = "#UserName";
param.Value = UserName;
SqlCommand CMD = new SqlCommand();
CMD.Connection = con;
CMD.CommandText = sql;
CMD.CommandType = System.Data.CommandType.Text;
SqlDataReader dr = CMD.ExecuteReader();
_adapter = new SqlDataAdapter
{
SelectCommand = new SqlCommand(sql, con)
};
_adapter.Fill(_dt);
List<Roles> roles = new List<Roles>(_dt.Rows.Count);
if (_dt.Rows.Count > 0)
{
foreach (DataRow studentrole in _dt.Rows)
{
roles.Add(new readRoles(studentrole));
}
}
var singlestu = roles.FirstOrDefault(e => e.UserName == userName);
return Ok(singlestu)
;
}
After much head-cracking, I go it to work by converting the UserName to type int in the Roles class and the source query.

How to get many field on the Query of webservice

I am making a web service get data from sql server. I need to get many fields from the sql server, but I can only get one field, which is the Currancy Name
namespace WebApplication2
{
public class DataHelper
{
public static string GetCurrency(string currencyCode)
{
string currencyName = "";
SqlConnection con = new SqlConnection(#"Data Source=WEB3\SHAREPOINT;Initial Catalog=WSS_Search_WEB3;Integrated Security=True");
SqlCommand cmd = new SqlCommand("select PO_NUMBER,PO_STATUS from View_1 where PO_HEADER_ID ='" + currencyCode.ToUpper() + "'", con);
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
currencyName = dr["PO_NUMBER"].ToString();
}
dr.Close();
con.Close();
return currencyName;
}
}
}
I need to get the PO_Number & PO Status from the Query
As I understand you need to return not only PO_NUMBER, but also PO_STATUS, and as I understand you want to return both values.
I suggest you make model that represent what you want to return.
So for that we make a model class call it for instance POModel:
public class POModel
{
public string currencyName { get; set; } // PO_Number
public string statusName { get; set; } // PO_Status
}
Than fetch the values from SQL as you did and return object in stead of string.
Here would you final code looks like, of course naming and all the stuff you can change the way if fits best:
public class DataHelper
{
public static POModel GetCurrency(string currencyCode)
{
//string currencyName = "";
var poModel = new POModel();
SqlConnection con = new SqlConnection(#"Data Source=WEB3\SHAREPOINT;Initial Catalog=WSS_Search_WEB3;Integrated Security=True");
SqlCommand cmd = new SqlCommand("select PO_NUMBER,PO_STATUS from View_1 where PO_HEADER_ID ='" + currencyCode.ToUpper() + "'", con);
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
poModel.currencyName = dr["PO_NUMBER"].ToString();
poModel.statusName = dr["PO_STATUS"].ToString();
}
dr.Close();
con.Close();
//return currencyName;
return poModel;
}
}
public class POModel
{
public string currencyName { get; set; }
public string statusName { get; set; }
}
One option is to return an array that contains the two values. Notice string[]:
public static string[] GetCurrency(string currencyCode)
Similar to how you declared string currencyName = "";, instead make an array variable:
string[] poData = new string[2];
Since this looks like it should return a single row, I would not loop. Just do a Read():
dr.Read();
poData[0] = dr["PO_NUMBER"].ToString(); //poData[] will have to be declared in your method
poData[1] = dr["PO_STATUS"].ToString();
....
return poData;

ASP.NET MVC pass parameter to stored procedure from controller without Entity Framework

ASP.NET MVC newbie here from a Webforms background. I'm trying to pass the logged in username value via HttpContext.User.Identity.Name to a stored procedure. I'm basically trying to check if the Username exists in the database table or not. I think I'm overlooking something as I'm not quite sure how to pass the User.Identity.Name value to the stored procedure so that it executes and returns a value that either exists or null/blank. Here's my code:
Data access layer class:
public LoggedUser GetLoggedUser(LoggedUser obj)
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["HWebb"].ConnectionString);
string UserName = "";
try
{
SqlParameter[] parameters ={
new SqlParameter("#USER_CRED",obj.User_Name),
};
SqlCommand cmd = CreateCommand("PortalWeb.GetSelect_User", parameters, con);
DataTable dt = new DataTable();
con.Open();
SqlDataAdapter ada = new SqlDataAdapter(cmd);
ada.Fill(dt);
foreach (DataRow dr in dt.Rows)
{
if (dr["USER_CRED"] != DBNull.Value)
UserName = Convert.ToString(dr["USER_CRED"]);
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
}
return obj;
}
Model:
public class LoggedUser
{
public string User_Name { get; set; }
}
Controller:
public ActionResult UserVerification()
{
DataAccess dac = new DataAccess();
LoggedUser objUser = new LoggedUser();
objUser = dac.GetLoggedUser(objUser);
if (HttpContext.User.Identity.Name != objUser.User_Name)
{
return RedirectToAction("Index", "Home");
}
return null;
}
This won't cause any errors, but I don't think the parameters are being passed correctly as the table returns a null value and I'm not sure if the HttpContext.User.Identity.Name value is even being passed in the first place.
Is there a way to pass the value from the controller to the stored procedure? I'm new to this so I'm sure there I'm missing some code to have this fully functional. I hope someone can help.
Thanks!
I changed the code to this and it works now, although I'm sure there's a better approach to it.
public string GetLoggedUser(string User_Name)
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["HWebb"].ConnectionString);
string UserName = "";
try
{
SqlParameter[] parameters ={
new SqlParameter("#USER_CRED", User_Name),
};
SqlCommand cmd = CreateCommand("PortalWeb.GetSelect_User", parameters, con);
DataTable dt = new DataTable();
con.Open();
SqlDataAdapter ada = new SqlDataAdapter(cmd);
ada.Fill(dt);
foreach (DataRow dr in dt.Rows)
{
if (dr["USER_CRED"] != DBNull.Value)
UserName = Convert.ToString(dr["USER_CRED"]);
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
}
return UserName;
}
Then in the Controller:
public ActionResult UserVerification()
{
DataAccess dac = new DataAccess();
string UserNameApp = HttpContext.User.Identity.Name;
string UserName = dac.GetLoggedUser(UserNameApp);
if (HttpContext.User.Identity.Name != UserName)
{
return redirecToAction("Index", "Home");
}
}
Yes, example in traditional way using Ado.net
Create table:
CREATE TABLE [dbo].[Employee](
[Empid] [int] NOT NULL,
[Name] [varchar](50) NULL,
[City] [varchar](max) NULL,
[Address] [varchar](max) NULL,CONSTRAINT [PK_Employee] PRIMARYKEYCLUSTERED ([Empid] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY])
Copy script and run in sql server
Now create stored procedure exactly it should match parameter in procedure and propertied from model from .net mvc
Create procedure [dbo].[AddNewEmpDetails] (
#Empid int,
#Name varchar (50),
#City varchar (max),
#Address varchar (max)
) as begin
Insert into Employee(Empid,Name,City,Address) values(#Empid,#Name,#City,#Address)
End
Write sql connection
public bool Insert<T>(string query,T obj) {
string connection = System.Configuration.ConfigurationManager.ConnectionStrings["Your_connection_name_from_web.config"].ConnectionString;
SqlConnection con = new SqlConnection(connection);
SqlCommand com = new SqlCommand(query, con);
com.CommandType = CommandType.StoredProcedure;
foreach (PropertyInfo pi in obj.GetType().GetProperties()) {
com.Parameters.AddWithValue("#" + pi.Name, pi.GetValue(obj, null)?.ToString());
}
con.Open();
int i = com.ExecuteNonQuery();
con.Close();
if (i >= 1) {
return true;
} else {
return false;
}
}
Write model
public class EmpModel {
[Display(Name = "Id")]
public int Empid { get; set; }
[Required(ErrorMessage = "First name is required.")]
public string Name { get; set; }
[Required(ErrorMessage = "City is required.")]
public string City { get; set; }
[Required(ErrorMessage = "Address is required.")]
public string Address { get; set; }
}
Note:validation is optional i used both BAL and DAL layer for one model.
Create action method
[HttpPost]
public ActionResult AddEmployees(EmpModel Emp) {
var status = AddEmployee("AddNewEmpDetails",Emp);
return View();
}
Summary: we should pass data to EmpModel.
now go and check in table data is inserted

Return Object in C#

I'm trying to return an object in C#. In JavaScript, I would do this:
function myFunction () {
var myObj = { firstName: "John", lastName: "Smith", age: 20};
return myObj;
}
Everything I'm reading about returning an object within C# is much different than this so it's throwing me for a loop.
What I want to do is run a query to SQL to get some user info and return the users Role, Full Name, Email, etc...
Here is my current C# Code:
public static string getUserRole(string connectionString, string userId)
{
string role;
SqlConnection sqlCon = new SqlConnection(connectionString);
SqlCommand sqlCom = new SqlCommand();
SqlDataReader reader;
sqlCom.CommandText = "SELECT Role FROM myDatabase.Table WHERE Email = '" + userId + "'";
sqlCom.CommandType = CommandType.Text;
sqlCom.Connection = sqlCon;
sqlCon.Open();
reader = sqlCom.ExecuteReader();
if (reader.Read())
{
role = reader.GetString(0);
sqlCon.Close();
return role;
}
else
{
return "An error has occurred";
}
}
I'm assuming I need to do something like the following but it doesn't work:
public static string getUserRole(string connectionString, string userId)
{
string role;
string fullName;
string email;
SqlConnection sqlCon = new SqlConnection(connectionString);
SqlCommand sqlCom = new SqlCommand();
SqlDataReader reader;
sqlCom.CommandText = "SELECT Role FROM myDatabase.Table WHERE Email = '" + userId + "'";
sqlCom.CommandType = CommandType.Text;
sqlCom.Connection = sqlCon;
sqlCon.Open();
reader = sqlCom.ExecuteReader();
if (reader.Read())
{
public class myObject
{
role = reader.GetString(0);
fullName = reader.GetString(1);
email = reader.GetString(2);
}
sqlCon.Close();
return myObject;
}
else
{
return "An error has occurred";
}
}
I'm probably way off but from what I'm reading, object within c# are basically classes. So that makes sense. I need to create a class that defines my properties. Is this correct? I've ready lots of posts and watched some youtube videos but none are 'clicking'
Thanks in advance for any helpful input.
public class UserInfo
{
public string role;
public string fullName;
public string email;
public string ErrorCode;
}
and then change signatures to
public static UserInfo getUserRole(string connectionString, string userId)
and then change
if (reader.Read())
{
public class myObject
{
role = reader.GetString(0);
fullName = reader.GetString(1);
email = reader.GetString(2);
}
sqlCon.Close();
return myObject;
}
else
{
return "An error has occurred";
}
to create an object of UserInfo and return that. Like,
UserInfo info = new UserInfo();
if (reader.Read())
{
info.role = reader.GetString(0);
info.fullName = reader.GetString(1);
info.email = reader.GetString(2);
sqlCon.Close();
}
else
{
info.ErrorCode = "An error has occurred";
}
return info;
Note: Not the best way to do it, but should get you going. Just to give you an idea.

Passing lot of parameters into Web Service

I have a web service in ASP.NET a simple one but the web method takes 5 parameters. Is there any other way to pass the parameters? like array or list?. I would like to limit it to 3.
I tried SetMethod(string param) and dint work.
Thanks.
Why don't you create a Class that has those parameters as it's properties, then you would pass an instance of the class as a parameter to the web method.
Changing something like this..
[WebMethod]
public void SomeMethod(string param1, string param2, string param3)
{
//some code
}
to something like this...
[WebMethod]
public void SomeMethod(SomeClass myClass)
{
//some code
}
public class SomeClass
{
public string Param1 { get; set; }
public string Param2 { get; set; }
public string Param3 { get; set; }
}
and you would use it like so...
SomeClass myClass = new SomeClass();
myClass.Param1 = "some data";
myClass.Param2 = "more data";
myClass.Param3 = "even more";
// make the webservice call
someObject.SomeMethod(myClass);
List<Student> list = new List<Student>();
[WebMethod]
public string InsertUserDetails(Student userInfo)
{
list.Add(userInfo);
//string Message;
SqlConnection con = new SqlConnection("Data Source=.;Initial Catalog=Sample;Integrated Security=True");
con.Open();
foreach (Student s in list)
{
SqlCommand cmd = new SqlCommand("insert into userdetail(username,password,country,email) values(#UserName,#Password,#Country,#Email)", con);
cmd.Parameters.AddWithValue("#UserName", userInfo.UserName);
cmd.Parameters.AddWithValue("#Password", userInfo.Password);
cmd.Parameters.AddWithValue("#Country", userInfo.Country);
cmd.Parameters.AddWithValue("#Email", userInfo.Email);
int result = cmd.ExecuteNonQuery();
}
//if (result == 1)
//{
// Message = userInfo.UserName + " Details inserted successfully";
//}
//else
//{
// Message = userInfo.UserName + " Details not inserted successfully";
//}
//con.Close();
// return Message;
return "done";
}
you can do like this>>>>>>>>>>>>>

Categories