I have an Web API craeted which calls the stored procedure, the stored procedure insert/updates and select a record in the Database. Insert/Update works, trying to convert the selected record that is read using ExecuteReader in to HTTPResponseMessage
[HttpGet]
public HttpResponseMessage Get(string Account)
{
if (string.IsNullOrEmpty(Account))
{
return Request.CreateResponse(new { error = "Input parameters cannot be Empty or NULL" });
}
string strcon = ConfigurationManager.ConnectionStrings["DBConnection"].ConnectionString;
SqlConnection DbConnection = new SqlConnection(strcon);
SqlDataReader reader = null;
DbConnection.Open();
SqlCommand command = new SqlCommand("[dbo].[usp_InserUpadte]", DbConnection);
command.CommandType = CommandType.StoredProcedure;
//create type table
DataTable table = new DataTable();
table.Columns.Add("AccountID", typeof(string));
table.Rows.Add(Account);
SqlParameter parameter = command.Parameters.AddWithValue("#account_TT", table);
parameter.SqlDbType = SqlDbType.Structured;
parameter.TypeName = "account_TT";
XmlReader xreader = command.ExecuteXmlReader();
List<QueryResult>qresults = new List<QueryResult>();
while (xreader.Read())
{
QueryResult qr = new QueryResult();
qr.AccountID = xreader["AccountID"].ToString();
qr.CounterSeq = xreader["CounterSeq"].ToString();
qresults.Add(qr);
}
I am not sure how to build the Response in XML, I created a class called QueryResult but I am not sure if this can be used in create the XML Response.
public class QueryResult
{
public string AccountID { get; set; }
public string CounterSeq { get; set; }
}
Also I am trying to write theresponse in the file when the API is executed. I havedone this with JSON and OracleDatabase earlier and not sure with this one. Any help is greatly appreciated.
You just need to return your qresults object and it will be automatically serialized into XML (or JSON). You can read how to add attributes to your QueryResult class to get the xml structured the way you would like it here JSON and XML Serialization in Web API
I would also recommend returning a IHttpActionResult instead of building a HttpResponseMessage up. Then you can simply do this at the end of your message and it will automatically be serialized based on the http ACCEPT header:
[HttpGet]
public IHttpActionResult Get(string Account)
{
// rest of implementation left out for readability...
return Ok(qresults);
}
Related
I need help with returning multiple values from my api to the httpclient post request but its returning null
api
[HttpPost("ShowUser")]
public (IEnumerable<UserInformation>, int) ShowUser([FromBody] Pagination pagination)
{ // retrieving data from database
var result = _showUsers.ShowManagerUsers(pagination.PageSize, pagination.skip, pagination.searchValue); // the output here is({System.Collections.Generic.List<Entities.UserInformation>}, 37) (note: 37 is the rows total)
Entities.PaginationResponse<IEnumerable<UserInformation>> paginationResponse = new Entities.PaginationResponse<IEnumerable<UserInformation>>
{
Data = result.Item1,
RowsCount = result.Item2
};
return (paginationResponse.Data, paginationResponse.RowsCount);
}
HttpClient Post Request
public async Task<(List<TOut>, TOut)> PostGetListRequest<TIn, TOut>(TIn content, string uri, string token)
{
...
using (response = await client.PostAsync(uri, serialized))
{
if (response.StatusCode.ToString() == "OK")
{
responseBody = response.Content.ReadAsStringAsync().Result;
var result = JsonConvert.DeserializeObject<(List<TOut>, TOut)>(responseBody);
return (result.Item1, result.Item2);
}
...
}
}
Output
Any idea what's wrong with my code?
Try changing your API code to this.
[HttpPost("ShowUser")]
public ActionResult ShowUser([FromBody] Pagination pagination)
{ // retrieving data from database
var result = _showUsers.ShowManagerUsers(pagination.PageSize, pagination.skip, pagination.searchValue); // the output here is({System.Collections.Generic.List<Entities.UserInformation>}, 37) (note: 37 is the rows total)
Entities.PaginationResponse<IEnumerable<UserInformation>> paginationResponse = new Entities.PaginationResponse<IEnumerable<UserInformation>>
{
Data = result.Item1,
RowsCount = result.Item2
};
return Ok((paginationResponse.Data, paginationResponse.RowsCount));
}
If this is is designed to be an API that others will consume, you really shouldn't be returning anonymous objects. I think it would be a better idea to either return a wrapper model, or simply return the pagingResponse model you already have.
[HttpPost("ShowUser")]
[ProducesResponseType(typeof(Entities.PaginationResponse<IEnumerable<UserInformation>>), StatusCodes.Status200OK)]
public ActionResult ShowUser([FromBody] Pagination pagination)
{ // retrieving data from database
var result = _showUsers.ShowManagerUsers(pagination.PageSize, pagination.skip, pagination.searchValue); // the output here is({System.Collections.Generic.List<Entities.UserInformation>}, 37) (note: 37 is the rows total)
Entities.PaginationResponse<IEnumerable<UserInformation>> paginationResponse = new Entities.PaginationResponse<IEnumerable<UserInformation>>
{
Data = result.Item1,
RowsCount = result.Item2
};
return Ok(paginationResponse);
}
Let me know if this doesn't work or if you need anything else.
Happy coding!
1-you should await for reading response content
responseBody = await response.Content.ReadAsStringAsync();
2-Make Sure the response in not empty.
3- i discourage using tuples as it violates the Object orinted and clean code practices
For the empty response body, if your project version is beyond ASP.NET Core 3.x, be sure add NewtonSoft support, check detailed steps in this answer
services.AddControllers()
.AddNewtonsoftJson();
Assume that the PostGetListRequest<TIn, TOut> method is invoked by using the following code, TOut is type of UserInformation class:
await GetListRequest<string, UserInformation>("xxx", "https://localhost:portNumber/xxx", "xxx");
So the deserialize type should be (List<UserInformation>, UserInformation).
var result = JsonConvert.DeserializeObject<(List<TOut>, TOut)>(responseBody);
But your API's return type is (IEnumerable<UserInformation>, int).
public (IEnumerable<UserInformation>, int) ShowUser([FromBody] Pagination pagination)
API's return type does not match the deserialize type. So you cannot deserialize successfully.
A working demo:
public async Task<(List<TOut>, int)> GetListRequest<TIn, TOut>(TIn content, string uri, string token)
{
HttpClient client = new HttpClient();
var response = await client.PostAsync(uri,serialized);
var responseBody = response.Content.ReadAsStringAsync().Result;
var result = JsonConvert.DeserializeObject<(List<TOut>, int)>(responseBody);
return (result.Item1, result.Item2);
}
Api:
[HttpPost("ShowUser")]
public (IEnumerable<UserInformation>, int) ShowUser([FromBody] Pagination pagination)
{ // retrieving data from database
var result = _showUsers.ShowManagerUsers(pagination.PageSize, pagination.skip, pagination.searchValue); // the output here is({System.Collections.Generic.List<Entities.UserInformation>}, 37) (note: 37 is the rows total)
Entities.PaginationResponse<IEnumerable<UserInformation>> paginationResponse = new Entities.PaginationResponse<IEnumerable<UserInformation>>
{
Data = result.Item1,
RowsCount = result.Item2
};
return (paginationResponse.Data, paginationResponse.RowsCount);
}
Result:
In my REST Service I have the following:
AssetController:
// GET: <AssetController>
[HttpGet("{companyID}/{machineName}")]
public Asset Get(int companyID, string machineName)
{
Database db = new Database(configuration.ConnectionString);
//DataSet ds = db.executeFunctionSelect("fngetallassets2()");
DataSet ds = db.executeViewSelect("tblasset where LOWER(name) = '" + machineName.ToLower() + "'");
//DataSet ds = db.executeDataSetProc("getallassets", null);
DataTable table = ds.Tables[0];
DataRow row = table.Rows[0];
Asset asset = new Asset
{
ID = int.Parse(row["ID"].ToString()),
CompanyID = int.Parse(row["Company_ID"].ToString()),
Name = row["Name"].ToString(),
IPAddress = row["IP_Address"].ToString(),
CreateDate = DateTime.Parse(row["Create_Date"].ToString()),
IsActive = bool.Parse(row["Is_Active"].ToString())
};
return asset;
}
This works fine... Its the PUT that I need help with
// PUT /<AssetController>/5
// Insert record into the database
[HttpPut("{asset}")]
public void Put([FromBody] string asset)
{
Database db = new Database(configuration.ConnectionString);
db.executeNonQuery("sp_AssetInsert", null);
}
Here I am trying to pass (somehow) the same asset class
In the calling windows forms I use this way to call the PUT Method:
public void InsertAsset(Asset asset)
{
ArrayList parameters = new ArrayList
{
asset.Name,
asset.IPAddress
};
RestClient client = new RestClient("https://localhost:5001/Asset/");
RestRequest request = new RestRequest(Method.PUT);
request.AddJsonBody(asset);
IRestResponse<List<string>> response = client.Execute<List<string>>(request);
if (response.StatusCode == HttpStatusCode.OK)
{
}
I get an error on Response.StatusCode = unsupportedmedia or something like this.
I need to know how to serialize or somehow pass either the class or the JSON string of it or whatever...
Can someone please help me figure out how to call the PUT methods as I have dozens of these to do.
Here is the calling and receiving code used to make this work.
calling:
RestClient client = new RestClient("https://localhost:5001/Asset/");
RestRequest request = new RestRequest(Method.PUT);
request.AddJsonBody(asset); <-- Asset is a class object
RestResponse response = (RestResponse)client.Execute(request);
if (response.StatusCode == HttpStatusCode.OK)
{
}
Receiving Code:
// PUT /<AssetController>/5
// Insert record into the database
[HttpPut]
public void Put([FromBody] Asset asset)
{
Database db = new Database(configuration.ConnectionString);
db.executeNonQuery("sp_AssetInsert", null);
}
I needed to change the [FromBody] string asset to [FromBody] Asset asset
There are several ways to pass parameters:
as url route i.e. https://localhost:5001/Asset/42/MyCompanyName
as url parameter http:// localhost:5001/Asset?companyID=42&machineName=companyname
in body, typically as a json serialized object
when you specify the route in [HttpPut("{paramaters}")] you are specifying option 1. You can use FromBody and FromUrl attributes on the parameter to control this. Simple parameters like numbers and string would typically be part of the URL, while complex objects like Asset will probably be easier to pass in the body.
See also
restsharp parameter posting
asp.net parameter binding
I would really appreciate it if you can point me to the right place or right idea. I have not done C# in ages and I am not sure what I am doing anymore.
Basically I have an Azure based MSSQL database that I need to read data from and return that data in JSON format for my iPhone app. Azure APIs do not allow you to read directly from the DB but you can build a .Net web API and use that - so that is where I went to.
I have gotten the first part to work. In that I can make a http request and Azure responds fine. I have also built the DB and tables and I have tested all that and it works. I have also tested the query and it runs well formatted JSON.
However, I need to pass the data in the data reader as an http response and I cannot figure that part out. Attached are the two vanilla files..one that makes the dummy http request and the other is the db connector file.
So in short, in the Function1.cs file I need to go from
:req.CreateResponse(HttpStatusCode.OK, "Hello" + name); to
:req.CreateResponse(HttpStatusCode.OK, );
First File: Function1.cs
namespace getOutageAlerts
{
public static class Function1
{
[FunctionName("Function1")]
public static async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
// parse query parameter
string name = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
.Value;
if (name == null)
{
// Get request body
dynamic data = await req.Content.ReadAsAsync<object>();
name = data?.name;
}
return name == null
? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body")
**:req.CreateResponse(HttpStatusCode.OK, "Hello" + name);**
}
}
}
Second File: DBConnector.cs
using System;
using System.Data.SqlClient;
public class DBConnector
{
public DBConnector()
{
SqlConnection getalertsConnection = new SqlConnection("Server=tcp:xxxxxxxxx.database.windows.net,1433;Initial Catalog=mckMobileAppsDB;Persist Security Info=False;User ID=xxxxxxx;Password=xxxxxxxx;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;");
SqlCommand cmd = new SqlCommand();
SqlDataReader reader;
cmd.CommandText = "SELECT Date_Created As Date, Incident_Number AS Incident, Flash_Summary AS Summary, Service, Business_Impact AS Impact, Incident_Status AS Status from OutagesMobileAppNotifications FOR JSON PATH, Root('Alerts')";
cmd.CommandType = CommandType.Text;
cmd.Connection = getalertsConnection;
getalertsConnection.Open();
reader = cmd.ExecuteReader();
// Data is accessible through the DataReader object here.
getalertsConnection.Close();
}
}
You're question is phrased a little awkwardly, plus the bad formatting doesn't help. However, it looks as though you want to return JSON from an Azure Serverless Function. Based on this assumption I'll try to answer.
To return JSON you will want to add the Newtonsoft.Json package. This is simple, at the top of your function add the following:
#r "Newtonsoft.Json"
using System.Net;
using System.Text;
using Newtonsoft.Json;
using System.Linq;
(Edit: Added using statement for System.Linq so the Select is available for the data reader.)
In the DBConnector you wrote I would convert the reader to an array of objects and then serialize that result to JSON. (I have truncated your list of fields to jsut 2 for brevity... you'll obviously need to add the whole list.)
var incidents = dataReader.Select(m => new { m.Date, m.Incident }).ToList();
var jsonResult = JsonConvert.SerializeObject(incidents, Formatting.Indented);
Then return the JSON.
return new HttpResponseMessage(HttpStatusCode.OK) {
Content = new StringContent(jsonResult, Encoding.UTF8, "application/json")
};
(I am trying to do this from memory... and I haven't done Azure Functions in about a year... so the exact code may differ.)
Additionally... since you haven't worked with C# in a while and maybe never with Azure Functions, it might be more simple to keep everything in the same function. By this I mean you don't have to have the second class/file... you can just put all the SQL work in your main method. I would normally consider this a bad practice, but in the short term it might ease your efforts.
In my latest project I want to have a user type in name and password on an Android phone, save it in JSON-format, and POST it to an ASP.NET MVC server which should return configuration data in a new JSON.
What I have so far:
Android (partial code):
String json = "{\"x\": \"val1\",\"y\":\"val2\"}";
URL url = new URL("http://xxxxx/Home/GetData");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json"); // have tried without this
conn.setRequestProperty("Content-Length", json.getBytes().length + "");
conn.setDoOutput(true);
os = conn.getOutputStream();
os.write(json.getBytes("UTF-8"));
os.close();
conn.connect();
The json string here is just for testing.
MVC:
[HttpPost]
public ActionResult GetData(String request)
{
Debug.WriteLine(request.Length); // not relevant to the question
var data = new { Name = "Test", Age = "39" };
return Json(data);
}
Returns JSON with test data.
The string argument in the MVC controller is probably wrong here. I have tried accepting e.g. byte[], but I always end up with NULL.
Any help with this or suggestions for alternatives is appreciated!
Cheers
If this is what's being posted to the server:
{
"x": "val1",
"y": "val2"
}
Then the method parameters should reflect those key/value pairs. Something like this:
public ActionResult GetData(string x, string y)
This will go through everything you post in the json. Prettu much like #David's but for when you have no clue whats being sendt to the GetData
public ActionResult GetData()
{
foreach (var key in Request.Form.AllKeys)
{
//This will iterate through everything in your post data
var value = Request.Form[key];
}
}
I have the following method which is supposed to return a JSONResult so I can use it in an AJAX method with javascript and load autocomplete suggestions for a textbox. I will load this everytime a particular dropdown list changes.
[AcceptVerbs(HttpVerbs.Post), Authorize]
private JsonResult GetSchemaNodeValues(string SchemaNodeId)
{
var query = #"Select ld.""Value""
From ""LookupData"" ld, ""SchemaNode"" sn
Where sn.""LookupTypeId"" = ld.""LookupTypeId""
And sn.""SchemaNodeId"" = '{0}'";
DataSet data = new DataSet();
data = ServiceManager.GenericService.ExecuteQuery(String.Format(query, SchemaNodeId)).Data;
var res = data.Tables[0].AsEnumerable().Select(dr => new
{
Value = dr["Value"].ToString()
});
return JsonConvert.SerializeObject(res);
}
I get the following error under return JsonConvert.SerializeObject(res);
Error 106 Cannot implicitly convert type 'string' to 'System.Web.Mvc.JsonResult'
Is there any way to get past this?
Before this I tried using System.Web.mvc.Controller.Json(res); which returns a JSONResult from an object.
But I couldn't use it because my class is a PageDialog not a Controller so it doesn't have access to Controller's protected internal methods like JSon(). The error I got was that JSon() is inaccessible due to its protection level. The Controller class was locked and I can't make it public or create a workaround so I changed the approach using JsonConvert.SerializeObject(res);
Any suggestions would be extremely welcome.
private dynamic GetSchemaNodeValues(string SchemaNodeId)
{
...
return data.Tables[0].AsEnumerable().Select(dr => new
{
Value = dr["Value"].ToString()
});
}
or
private string GetSchemaNodeValues(string SchemaNodeId)
{
...
var result = data.Tables[0].AsEnumerable().Select(dr => new
{
Value = dr["Value"].ToString()
});
return JsonConvert.SerializeObject(result);
}