Chnage format return of DotNet - asp.net

I created web API using dotNet. It work but i got a little problem.
This is my controller
WaybillDataAccessLayer objway = new WaybillDataAccessLayer();
public IEnumerable<Waybill> Get(string id_wb)
{
List<Waybill> lstWaybill = new List<Waybill>();
lstWaybill = objway.GetWaybill(id_wb).ToList();
return lstWaybill;
}
and my Models(WaybillDataAccessLayer)
public IEnumerable<Waybill> GetWaybill(String id_wb)
{
List<Waybill> lswaybill = new List<Waybill>();
using (SqlConnection con = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand("spGetWaybill", con); //Stored procedure on database
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#waybill", id_wb);
con.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read()) //foreach
{
Waybill wb = new Waybill();
wb.waybill = rdr["waybill"].ToString();
wb.deskripsi = rdr["deskripsi"].ToString();
wb.tanggal = rdr["tanggal"].ToString();
wb.pengirim = rdr["pengirim"].ToString();
wb.lokasi = rdr["lokasi"].ToString();
wb.penerima = rdr["penerima"].ToString();
lswaybill.Add(wb);
}
con.Close();
}
return lswaybill;
}
when i run this API,the output will be like this
[
{
"waybill": "00000093",
"deskripsi": "SPARE PARTS",
"tanggal": "19990727",
"pengirim": "JIEP",
"lokasi": "HO",
"penerima": "JKHO"
}
]
My Question is
how to remove that [] ?
how to add another information like
{
"status" : "sucess",
"data" { }
}
Thankyou for your help.

You're returning a list of WayBill objects. If you don't want the resulting JSON to be an array, then you need to just return a single WayBill, not a List. And if you want to wrap that in more data, then create a type to represent that information, populate an instance of it, and return it.
Since you're retrieving these objects by ID, I'm assuming there should be only one WayBill for any given ID. Thus you can simplify your data access layer.
public Waybill GetWaybill(String id_wb)
{
using (SqlConnection con = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand("spGetWaybill", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#waybill", id_wb);
con.Open();
SqlDataReader rdr = cmd.ExecuteReader();
rdr.Read();
Waybill wb = new Waybill();
wb.waybill = rdr["waybill"].ToString();
wb.deskripsi = rdr["deskripsi"].ToString();
wb.tanggal = rdr["tanggal"].ToString();
wb.pengirim = rdr["pengirim"].ToString();
wb.lokasi = rdr["lokasi"].ToString();
wb.penerima = rdr["penerima"].ToString();
return wb;
}
}
And add the type to wrap your response:
class GetWayBillResponse()
{
public string Status { get; set;}
public WayBill WayBill { get; set; }
}
Note that adding a status here isn't really all that helpful if you're seeing the object, you can assume it was successful. Also, the API would have responded with an HTTP 200 OK status code. So it's really superfluous.
Now your controller becomes:
WaybillDataAccessLayer objway = new WaybillDataAccessLayer();
public GetWayBillResponse Get(string id_wb)
{
GetWayBillResponse response = new GetWayBillResponse();
response.Status = "Success";
response.WayBill = objway.GetWaybill(id_wb);
return response;
}
Note that you can simplify your data access even further. You're manually assigning the result columns to the WayBill object. That's repetitive and boring. If you use an Object Relational Mapper such as Dapper, you can remove a lot of that boiler plate code.
Here's what it'd look like using Dapper:
public Waybill GetWaybill(String id_wb)
{
using (SqlConnection con = new SqlConnection(connectionString))
{
return con.QuerySingle<WayBill>("spGetWaybill", new { waybill = id_web }, commandType: CommandType.StoredProcedure);
}
}

Related

Web API to query SQL Server and return result is not working as expected

I am trying to connect to SQL Server from the Web API and return a result set as JSON. But my code shown here is not working as expected. I am trying to return the entire query response as a JSON:
[HttpGet]
public HttpResponseMessage Getdetails(string ROOM)
{
string commandText = "SELECT * from [TDB].[dbo].[results_vw] where ROOM = #ROOM_Data";
string connStr = ConfigurationManager.ConnectionStrings["TDBConnection"].ConnectionString;
var jsonResult = new StringBuilder();
using (SqlConnection connection = new SqlConnection(connStr))
{
SqlCommand command = new SqlCommand(commandText, connection);
command.Parameters.Add("#ROOM_Data", SqlDbType.VarChar);
command.Parameters["#ROOM_Data"].Value = ROOM;
connection.Open();
var reader = command.ExecuteReader();
if (!reader.HasRows)
{
jsonResult.Append("[]");
}
else
{
while (reader.Read())
{
jsonResult.Append(reader.GetValue(0).ToString());
}
}
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
response.Content = new StringContent(jsonResult.ToString());
connection.Close();
return response;
}
}
This code returns this result:
333838362692368203368203368203362692368203359544362692368203362692368203362692368203368203
Where I am expecting the JSON as
{"data":
[
{"R_ID":"368203","ROOM":"K2"},
{"R_ID":"368203","ROOM":"K2"}
]}
Now I created a model class called DatabaseResult to store the response but I am not sure how I can store the result in to the model class in the controller
public class DatabaseResult
{
public int r_id { get; set; }
public string room { get; set; }
}
The current result is because you are only return the the value from the first column of each row and adding it to the string builder.
Create a new instance of the model and populate it using the values from the reader for each row.
[HttpGet]
public IHttpActionResult Getdetails(string ROOM) {
string commandText = "SELECT * from [TDB].[dbo].[results_vw] where ROOM = #ROOM_Data";
string connStr = ConfigurationManager.ConnectionStrings["TDBConnection"].ConnectionString;
var jsonResult = new StringBuilder();
using (SqlConnection connection = new SqlConnection(connStr)) {
using (SqlCommand command = new SqlCommand(commandText, connection)) {
command.Parameters.Add("#ROOM_Data", SqlDbType.VarChar);
command.Parameters["#ROOM_Data"].Value = ROOM;
connection.Open();
List<DatabaseResult> records = new List<DatabaseResult>();
using (var reader = command.ExecuteReader()) {
while (reader.Read()) {
var row = new DatabaseResult {
r_id = (int)reader["r_id"],
room = (string)reader["room"],
//...other properties.
};
records.Add(row);
}
return Ok(records);
}
}
}
}
The above uses the column names as the indexer to get the values from the reader.

Getting a JSON string response from web method

In my web application there is a WCF web service. In the following method
public string GetPolicyDetails(GetPolicyDetails_ML ml)
{
var strFileName = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"log.xml");
DataTable dt = new DataTable();
DataSet ds = new DataSet();
try
{
con = new SqlConnection(connectionString);
con.Open();
cmd = new SqlCommand("sp_GetPolicyDetails", con) { CommandType = CommandType.StoredProcedure };
cmd.Parameters.AddWithValue("#policy_id", ml.policyID);
adp = new SqlDataAdapter(cmd);
adp.Fill(dt);
string json = JsonConvert.SerializeObject(dt,Formatting.Indented);
return json;
}
catch (SqlException ex)
{
return "fail";
}
finally
{
con.Close();
con.Dispose();
}
}
will return a json string inWCF Test Client. I need to access this method from my tab application. The code i used is
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
var ds = await client.GetPolicyInfoAsync(Convert.ToInt16(txtPolicyNumber.Text));
This will get the response in to the #var ds#. My question is what is the type of this var ds and how to get the Json data out of this variable ds. Thanks in advance.

Passing SqlParameter in webmethod asp.net

I am trying to create a web service which will help to execute stored procedure. And that web method I am calling in my code to execute a stored procedure. This is my web method -
[WebMethod(Description = des_ExecuteParamerizedSelectCommand)]
public DataTable ExecuteParamerizedSelectCommand(string CommandName, CommandType cmdType, SqlParameter[] param)
{
DataTable table = new DataTable();
using (SqlConnection con = new SqlConnection(ConnectionString()))
{
using (SqlCommand cmd = con.CreateCommand())
{
cmd.CommandType = cmdType;
cmd.CommandText = CommandName;
cmd.Parameters.AddRange(param);
try
{
if (con.State != ConnectionState.Open)
{
con.Open();
}
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(table);
}
}
catch
{
throw;
}
}
}
return table;
}
Now this is my code in my data access layer - when I am trying to call this web method, its throwing compile time error.
Error 2 Argument 2: cannot convert from 'System.Data.CommandType' to 'DAL.sqlDBHelper.CommandType'
Error 3 Argument 3: cannot convert from 'System.Data.SqlClient.SqlParameter[]' to 'DAL.sqlDBHelper.SqlParameter[]'
My code to call the webmethod -
sqlDBHelper.ODCdbHelper mysqlDBHelper = new sqlDBHelper.ODCdbHelper();
public Login GetUserRoles(string _Idsid)
{
Login login = null;
SqlParameter[] parameters = new SqlParameter[]
{
new SqlParameter("#UserName", _Idsid)
};
//Lets get the list of all employees in a datataable
using (DataTable table = mysqlDBHelper.ExecuteParamerizedSelectCommand("GetUserRole", CommandType.StoredProcedure, parameters))
Can you please tell me someone, where I am wrong??
Thanks in advance
Gulrej
Try like this
DAL.sqlDBHelper.SqlParameter[] parameters = new DAL.sqlDBHelper.SqlParameter[]//Change Here {
SqlParameter("#UserName", _Idsid)
};
//Lets get the list of all employees in a datataable
using (DataTable table = mysqlDBHelper.ExecuteParamerizedSelectCommand("GetUserRole", DAL.sqlDBHelper.CommandType.StoredProcedure, parameters))
I presume DAL.sqlDBHelper.CommandType will be an enumerator in your data access layer.
And the expected parameter is DAL.sqlDBHelper.SqlParameter[] instead of System.Data.SqlClient.SqlParameter[]
So you might call the select function as
DAL.sqlDBHelper.SqlParameter[] parameters = new DAL.sqlDBHelper.SqlParameter[]
{
new SqlParameter("#UserName", _Idsid)
};
using (DataTable table = mysqlDBHelper.ExecuteParamerizedSelectCommand("GetUserRole", DAL.sqlDBHelper.CommandType.StoredProcedure, parameters))
Please check what is the command type defined for stored procedures in your DAL.

storing data results from stored procedures

I have 2 arraylists. One is principleList which contains integer values that denotes roles (Admin, Project Manager etc.). Second is codeList which contains the various codes (e.g. AddUserProfile) for which I want to get permissions. I have a stored procedure "AllowedToPerformFunction" that returns allowed =0 or 1 depending on if a role can perform a code.
I am having trouble with the logic for this since I have multiple ids and multiple codes. For each id, I need to call the stored procedure with each code and store this.
I am trying to store permissions in a hashtable for various roles such as Admin, Project Manager. So for example for Admin i would need to store:
Admin (id =1)
code = "AddUser",allowed =1
code="AddProject",allowed=0
hashtable format (key,value) = (1, AddUser-1), (1, AddProject-0)
Here is my code that isn't working:
protected void Page_Load(object sender, EventArgs e)
{
getPermissions();
}
void getPermissions()
{
using (SqlConnection conn = new SqlConnection("GoalFishConnectionString")){conn.Open();
ArrayList idList = getPrincipleIds();
ArrayList codeList = getCodes();
ArrayList allowList = new ArrayList();
for (int i = 0; i < idList.Count; i++)
{
MessageBox.Show(idList[i].ToString());
for (int j = 0; j < codeList.Count; j++)
{
MessageBox.Show(codeList[j].ToString());
SqlCommand command2 = new SqlCommand("AllowedToPerformFunction", conn);
command2.CommandType = CommandType.StoredProcedure;
command2.Parameters.Clear();
command2.Parameters.Add("#principalID", SqlDbType.Int).Value = idList[i];
command2.Parameters.Add("#contextID", SqlDbType.Int).Value = idList[i];
command2.Parameters.Add("#roleCode", SqlDbType.VarChar).Value = codeList[j];
command2.Parameters.Add("#allowed", SqlDbType.Int);
command2.Parameters["#allowed"].Direction = ParameterDirection.Output;
command2.ExecuteNonQuery();
int allowed = (int)command2.Parameters["#allowed"].Value;
allowList.Add(command2.Parameters["#allowed"].Value);
}
}}}
ArrayList getPrincipleIds()
{
ArrayList principleList = new ArrayList();
using (SqlConnection conn = new SqlConnection("GoalFishConnectionString")){
conn.Open();
SqlCommand cmd = new SqlCommand("GetPrinciples", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
principleList.Add(rdr["unit_id"]);
}
rdr.Close();
}
return principleList;
}
ArrayList getCodes()
{
ArrayList codesList = new ArrayList();
using (SqlConnection conn = new SqlConnection("GoalFishConnectionString")){
conn.Open();
SqlCommand command = new SqlCommand("GetCodes", conn);
command.CommandType = CommandType.StoredProcedure;
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
codesList.Add(reader["Code"]);
//MessageBox.Show(reader["Code"].ToString());
}
reader.Close();
}
}
return codesList;
}
Any advice or help with this would greatly be appreciated.
Why not make a class like this and store it in the session? This way you only have to worry about permissions for one user (unless a user can be admin & Project Manager at the same time)
public class LoginUser
{
public loginUser
{
this.Permission = LoadAllPermissions()
}
public string Role { get; set; }
public Dictionary<integer, string> Permission { get; set; }
}

Asp.Net: Returning a DataSet from a Class

I've decided to start another thread based on the responses I got in this thread:
Asp.Net: Returning a Reader from a Class
I was returning a reader, but members have suggested I'd be better off returning a Dataset instead and also try to seperate the data access tier from the presentation tier.
This is what I have so far:
//my class methods
public DataSet GetSuppliers()
{
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand("con_spSuppliersList", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#blogid", HttpContext.Current.Request.QueryString["p"]);
return FillDataSet(cmd, "SuppliersList");
}
//my FillDataSet method
private DataSet FillDataSet(SqlCommand cmd, string tableName)
{
SqlConnection conn = new SqlConnection(connectionString);
cmd.Connection = conn;
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
try
{
conn.Open();
adapter.Fill(ds, tableName);
}
finally
{
conn.Close();
}
return ds;
}
// on my ascx page I call the method like so:
protected void Page_Load(object sender, EventArgs e)
{
//instantiate our class
MyClass DB = new MyClass();
// grab the table of data
DataTable dt = DB.GetSuppliers().Tables["SuppliersList"];
//loop through the results
foreach (DataRow row in dt.Rows)
{
this.supplierslist.InnerHtml += Server.HtmlEncode(row["Address"].ToString()) + "<br/>";
this.supplierslist.InnerHtml += "<b>Tel: </b>" + Server.HtmlEncode(row["Telephone"].ToString()) + "<p/>";
}
}
}
Would anyone like to suggest improvements?
Is my loop 'data tier' or 'presentation tier', should the loop be inside the class and I just return a formatted string instaed of a dataset?
Thanks for all the great advice
I also would use a Typed DataSet or create your own class that holds the properties so you are not dealing with strings like row["Address"] you would say object.Address and get compile time checking.
DataSets have a lot of built in functionality that is nice but also caries with it a lot of overhead that might not be needed in something simple. Creating a simple class with properties and passing that out of your data access layer is probably the simplest way to implement what you want.
Something like this on the DAL (Data Access Layer) side:
//Also pass in the blogID dont have the DAL get the value from the UI layer..
//make the UI layer pass it in.
public IList<Supplier> GetSuppliers(string connectionString, int blogID)
{
IList<Supplier> suppliers = new List<Supplier>();
//wrap with the using statements
using (SqlConnection conn = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand("con_spSuppliersList", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#blogid", blogID);
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
suppliers.Add(new Supplier
{
Address = reader.GetString(0),
Telephone = reader.GetString(1)
});
}
}
}
return suppliers;
}
}
public class Supplier
{
//I would have Address an object....but you have as string
//public Address Address { get; set; }
public string Address { get; set; }
public string Telephone { get; set; }
}
//Example if you went with Address class...
public class Address
{
//Whatever you want in the address
public string StreetName { get; set; }
public string Country { get; set; }
public string Region { get; set; }
public string City { get; set; }
}
One thing you should get in the habit of doing is calling Dispose() on your SqlConnection. The best pattern to do this is to use the using statement, which will automatically dispose of it for you. It looks like this:
private DataSet FillDataSet(SqlCommand cmd, string tableName)
{
using(SqlConnection conn = new SqlConnection(connectionString))
{
cmd.Connection = conn;
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
try
{
conn.Open();
adapter.Fill(ds, tableName);
}
finally
{
conn.Close();
}
return ds;
}
}
What you have in the foreach loop in Page_Load, is presentation logic (layout), and IMO this should not be in the code-behind of your page, but in the markup.
I'd suggest that instead of using a foreach loop to construct the HTML output, you should use a databound control (such as a asp:Repeater, DataList or GridView). Then you can bind the repeater to your dataset or datatable and have all the markup where it belongs (in the ASCX file). See this page for an example.
As a general note: you can find lots of tutorials on www.asp.net, e.g. about data access: http://www.asp.net/%28S%28pdfrohu0ajmwt445fanvj2r3%29%29/learn/data-access/

Resources