Web API to query SQL Server and return result is not working as expected - asp.net

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.

Related

Chnage format return of DotNet

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);
}
}

Calling an API on Xamarin getting Bad Request

So, I'm new to Xamarin and I'm trying to call API. I didn't have any trouble when I want to get data from a wheather api. But when I try to call my own API which is created with ASP.NET RESTFull and help of internet.
So this is my code. I can get what I need when I use ;
http://localhost:1658/api/person
on my browser, it works perfectly. But when I use;
string querystring = "http://10.0.2.2:1658/api/person";
JContainer results = await GetDataFromService(querystring);
}
public static async Task<JContainer> GetDataFromService(string queryString)
{
HttpClient client = new HttpClient();
var response = await client.GetAsync(queryString);
JContainer data = null;
if (response.IsSuccessStatusCode)
{
string json = response.Content.ReadAsStringAsync().Result;
data = (JContainer)JsonConvert.DeserializeObject(json);
}
return data;
}
it didn't work.
This is my API codes:
// This code piece in PersonController.cs
// GET: api/Person
public ArrayList Get()
{
PersonPersistance pp = new PersonPersistance();
return pp.getPersons();
}
// This piece of code in PersonPersistance.cs
public Person getPerson(long ID)
{
Person p = new Person();
//MySql.Data.MySqlClient.MySqlDataReader MSR = null;
SqlDataReader MSR = null;
string selectquery = "select * from person where Id="+ID.ToString();
//MySql.Data.MySqlClient.MySqlCommand cmd = new MySql.Data.MySqlClient.MySqlCommand(selectquery,conn);
SqlCommand cmd = new SqlCommand(selectquery, conn);
//MSR = cmd.ExecuteReader();
MSR = cmd.ExecuteReader();
if(MSR.Read())
{
p.Id = MSR.GetInt32(0);
p.FirstName = MSR.GetString(1);
p.LastName = MSR.GetString(2);
p.Pay = MSR.GetInt32(3);
p.BeginDay = MSR.GetDateTime(4);
p.EndDate = MSR.GetDateTime(5);
return p;
}
else
{
return null;
}
}
Try adding await to your ReadAsStringAsync():
public static async Task<JContainer> GetDataFromService(string queryString)
{
HttpClient client = new HttpClient();
var response = await client.GetAsync(queryString);
JContainer data = null;
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
data = JsonConvert.DeserializeObject<JContainer>(json);
}
return data;
}

.NET run stored procedure, get output

I am running this stored procedure with .NET like so:
public List<showWhatClass> showWhatMethod(string deviceWhat, int tagWhat, Decimal latit, Decimal longit, int Process, string CallNext, int CallNextVar)
{
showWhatCell = new List<showWhatClass>();
try
{
using (connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand("iosShowWhat", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#DeviceId", deviceWhat);
command.Parameters.AddWithValue("#TagId", tagWhat);
command.Parameters.AddWithValue("#Latitude", latit);
command.Parameters.AddWithValue("#Longitude", longit);
command.Parameters.AddWithValue("#Process", Process);
command.Parameters.AddWithValue("#CallNext", CallNext);
command.Parameters.AddWithValue("#CallNextVar", CallNextVar);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
showWhatClass item = new showWhatClass();
item.CallNext = reader.GetValue(0).ToString();
item.CallNextVar = (int)reader.GetValue(1);
showWhatCell.Add(item);
}
}
}
}
finally
{
connection.Close();
}
return showWhatCell;
}
The stored procedure returns the following message:
When I run this I get the following returned:
<ArrayOfshowWhatClass xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/WebServiceAPI.Models"/>
which is empty
my question is what am I doing wrong, how come nothing is returning when I run this with .NET but does return the message in SQL Server.
Here is my showWhatClass
public class showWhatClass
{
public string CallNext { get; set; }
public int CallNextVar { get; set; }
}
Try to change your parameters:
command.Parameters.AddWithValue("#DeviceId", deviceWhat);
to the following:
command.Parameters.Add("#DeviceId", SqlDbType.Int).Value = deviceWhat;

Losing first record and the values keep changing when loading reader to datatable

I load reader to my table like this
connection.Open();
sqlCmd = new SqlCommand(sqlCmd.CommandText, connection);
SqlDataReader sqlReader = sqlCmd.ExecuteReader();
DataTable dt = new DataTable();
sqlReader.Read();
dt.Load(sqlReader);
But it looks like I cannot retrieve the first record of fetch data.
The second problem is when I call the reader several times after that:
string comName = dt.Rows[0]["companyName"].ToString();
//To get address
sqlCmd.CommandText = addr;
sqlCmd.Parameters.AddWithValue("companyName", comName);
using (var addressReader = sqlCmd.ExecuteReader())
{
if (addressReader.Read())
{
Label1.Text = Label1.Text + " " + addressReader["address"].ToString();
}
}
//To get keyProcesses
sqlCmd.Parameters.Clear();
sqlCmd.CommandText = keyProcesses;
sqlCmd.Parameters.AddWithValue("companyName", comName);
using (var keyProcessesReader = sqlCmd.ExecuteReader())
{
if (keyProcessesReader.Read())
{
Label1.Text = Label1.Text + " " + keyProcessesReader.GetString(0);
}
}
But I find out that these reading also may changes the value of my datatable dt above! How could I only load data to dt at the first reading and keep it there without changing any more ?
Ps: In attempt to overcome the second problem, I am trying to store dt values in list
public class CompanyModel
{
public string compnName { get; set; }
public string compnAddress { get; set; }
public string compnKeyProcesses { get; set; }
public string compnStandards { get; set; }
}
then
List<CompanyModel> companies = new List<CompanyModel>();
for(int i = 0; i < dt.Rows.Count; i++)
{
companies.Add(new CompanyModel
{
compnName = dt.Rows[i]["companyName"].ToString(),
compnAddress = dt.Rows[i]["address"].ToString()
});
}
companyRepeater.DataSource = companies;
companyRepeater.DataBind();
Now, how do I access each company name in the list to make query on that name value accordingly, then input the new result to the list?
I tried:
foreach(List<Component> compnName in companies.Contains("companyName")
{
sqlCmd.CommandText = getKey;
sqlCmd.Parameters.AddWithValue("companyName", compnName);
using (var keyReader = sqlCmd.ExecuteReader())
{
if (keyReader.Read())
{
companies.Add(new CompanyModel compnKeyProcesses = keyReader.GetString("key"));
}
}
sqlCmd.CommandText = getstandard;
sqlCmd.Parameters.AddWithValue("companyName", compnName);
using (var standardReader = sqlCmd.ExecuteReader())
{
if (standardReader.Read())
{
companies.Add(new CompanyModel compnStandards = keyReader.GetString("standards"));
}
}
Try this for your first problem
SqlDataAdapter sdr = new SqlDataAdapter(sqlCmd.CommandText, connection);
DataTable dt=new DataTable();
sdr.Fill(dt);
you can display this whole data as a matter of confirmation by taking a datagridview
dataGridView1.DataSource=dt;

Manually converting result dataset to JSON

I have DataReader that holds the results from a stored procedure caal. The results consist of two fields ...
UserID
UserName
Normally I bind these results to an ASP.NET dropdownlist control ...
ddlUserList.DataSource = rdr // rdr is the DataReader
ddlUserList.DataTextField = "UserName"
ddlUserList.DataValueField = "UserID"
ddlUserList.DataBind()
However I am now trying to accomplish the same thing using jQuery AJAX. What I am stuck on is how to manually convert the dataset held in the DataReader to JSON. How are multiples values separated? Does this look correct?
{{"UserID":1, "UserName":"Bob"}, {"UserID":2, "UserName":"Sally"},{"UserID":3, "UserName":"Fred"}}
I realize there are libraries out there such as JSON.NET to handle the serialization but I am in the learning stage now and want to make sure I understand everything from the bottom up.
Was wondering if you have tried using System.Web.Script.Serialization.JavaScriptSerializer library?
You can look at Rick Stahl's blog on this:
http://www.west-wind.com/weblog/posts/737584.aspx
Or you could also do something like create a method that will pull out data from the datareader and place it in a list of objects. (See code below). These list of object will be serialized using the JavaScriptSerializer library.
Hope this helps!
public class User
{
public int UserId { get; set; }
public string UserName { get; set;}
}
public class DataLayer
{
public string GetUsers(string connString)
{
string result = null;
List<User> users = null;
// get data using SqlReader
using(var conn = new SqlConnection(connString))
{
using(var cmd = new SqlCommand{ Connection = conn, CommandText = "SELECT * FROM Users", CommandType = CommandType.Text })
{
conn.Open();
var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
if(!reader.HasRows)
return null;
//convert data reader to a list of user objects
users = (List<User>)ConvertToList<User>(ref reader);
conn.Close();
}
}
//convert list of objects in list to json objects
var jsonSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
result = jsonSerializer.Serialize(users);
return result;
}
public static IList<T> ConvertToList<T>(ref SqlDataReader reader)
{
IList<T> result = null;
if (reader.IsClosed)
return result;
result = new List<T>();
T item = default(T);
while (reader.Read())
{
//create item instance
item = (T)Activator.CreateInstance<T>();
//get class property members
var propertyItems = item.GetType().GetProperties();
//populate class property members with data from data reader
for (int ctr = 0; ctr < reader.FieldCount; ctr++)
{
if(reader.GetName(ctr) == propertyItems[ctr].Name)
propertyItems[ctr].SetValue(item, UtilsHelper.GetValue<string>(reader[ctr]), null);
}
//add item to list
result.Add(item);
}
reader.Close();
reader.Dispose();
return result;
}
}

Resources