Is it possible to call api with params object[] as parameter
[HttpGet("{procName}/{parametarList}")]
public ActionResult<string> Get(string procName , params object[] parametarList)
{
string JSONString = string.Empty;
using (var ado = new ADO())
{
var ds = ado.ExecuteAndReturnDS("execute " + procName " #0, #1, #2,#3,#4,#5", parametarList);
JSONString = JsonConvert.SerializeObject(ds.Tables[0]);
return new JsonResult(JSONString);
}
}
public DataSet ExecuteAndReturnDS(string upit, params object[] parametri)
{
try
{
_Conn();
command = new SqlCommand(upit, _Conn);
command.CommandTimeout = 200;
_ds = new DataSet();
_sqlda = new SqlDataAdapter(command);
for (int i = 0; i <= parametri.Count() - 1; i++)
{
if (parametri[i] == null)
{
command.Parameters.AddWithValue("#" + i, DBNull.Value);
}
else
{
command.Parameters.AddWithValue("#" + i, parametri[i]);
}
}
_sqlda.Fill(_ds);
if (_Conn.State == ConnectionState.Open)
{
_sqlda.Dispose();
_Conn.Dispose();
_Conn.Close();
}
return _ds;
}
catch (Exception ex)
{
return null;
}
}
Like this
/api/values/myProcedure/param1/param2/param3/param4/etc/
I can see 2 ways you can do it.
The first one is to pass in the parameterlist as just a string and then split it into an array of objects in the method.
Here is an example of how you can easily split a string in C#: https://learn.microsoft.com/en-us/dotnet/csharp/how-to/parse-strings-using-split
The second is to use a POST request instead of a GET request, this would allow you to pass in more complicated objects.
Related
I'm trying to come up with a way just to load a table from SQL Server into a class, without having to tell it anything. Basically, just create the class and have it know what to load, based on that. Here's what I have so far.
My question is, is there some way to keep from having to hard code the types, to call reader.readString, reader. readInt32, etc.. based on the FieldType?
private Int32? readInt32(SqlDataReader reader, string columnName)
{
Int32? result = null;
if (!reader.IsDBNull(reader.GetOrdinal(columnName)))
{
result = reader.GetInt32(reader.GetOrdinal(columnName));
};
return result;
}
public List<T> readTable(string table, string wherecls, string connStr)
{
List<T> result = new List<T>();
using (SqlConnection connection = new SqlConnection(connStr))
{
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "select * from " + table;
if (wherecls.Length > 0) command.CommandText += " where " + wherecls;
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
Object i = Activator.CreateInstance(typeof(T));
System.Reflection.FieldInfo[] fieldInfoList = typeof(T).GetFields();
foreach (System.Reflection.FieldInfo f in fieldInfoList)
{
if (f.FieldType == typeof(string)) f.SetValue(i, readString(reader, f.Name));
if (f.FieldType == typeof(Int32)) f.SetValue(i, readInt32(reader, f.Name));
if (f.FieldType == typeof(Int16)) f.SetValue(i, readInt16(reader, f.Name));
if (f.FieldType == typeof(byte)) f.SetValue(i, readByte(reader, f.Name));
if (f.FieldType == typeof(short)) f.SetValue(i, readShort(reader, f.Name));
}
result.Add((T)i);
}
}
}
}
return result;
}
Thank you,
Dan Chase
What you describe is a lot of work... and is exactly what tools like "dapper" already do. So my suggestion here: use dapper:
// Dapper adds a Query<T>(this DbConnection, ...) extension method
var data = connection.Query<T>(sql, args).AsList();
I would, however, say that string wherecls sends shivers down my spine - that sounds like a SQL injection nightmare. But... that's up to you.
Try this.
Make sure the type has a public default constructor--one that takes no arguments--and that the column names in the SQL string exactly match the name of the type's public properties.
namespace MyNamespace {
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Reflection;
public static class MyExtensions {
public static IEnumerable<T> Query<T>(this SqlConnection cn, string sql) {
Type TypeT = typeof(T);
ConstructorInfo ctor = TypeT.GetConstructor(Type.EmptyTypes);
if (ctor == null) {
throw new InvalidOperationException($"Type {TypeT.Name} does not have a default constructor.");
}
using (SqlCommand cmd = new SqlCommand(sql, cn)) {
using (SqlDataReader reader = cmd.ExecuteReader()) {
while (reader.Read()) {
T newInst = (T)ctor.Invoke(null);
for (int i = 0; i < reader.FieldCount; i++) {
string propName = reader.GetName(i);
PropertyInfo propInfo = TypeT.GetProperty(propName);
if (propInfo != null) {
object value = reader.GetValue(i);
if (value == DBNull.Value) {
propInfo.SetValue(newInst, null);
} else {
propInfo.SetValue(newInst, value);
}
}
}
yield return newInst;
}
}
}
}
}
}
Maybe my solution is a bit better. I populate type T using extension with handling null values and populating properties in order I like.
Example:
public async Task<ObservableCollection<T>> Search_data<T>()
{
var data = new ObservableCollection<T>();
try
{
using (OracleConnection con = new OracleConnection(connn_string))
{
con.Open();
OracleCommand cmd = new OracleCommand("MySchema.SomeTable", con)
{
CommandType = CommandType.StoredProcedure
};
cmd.Parameters.Add("result", OracleDbType.RefCursor, ParameterDirection.Output);
using (OracleDataReader rdr = cmd_iskanje_apo.ExecuteReader())
{
while (await rdr.ReadAsync())
{
var item = Activator.CreateInstance<T>();
item.SetValue("NAME", rdr.IsDBNull(0) ? null : rdr.GetString(0));
item.SetValue("SURNAME", rdr.IsDBNull(1) ? null : rdr.GetString(1));
item.SetValue("ADDRESS", rdr.IsDBNull(2) ? null : rdr.GetString(2));
data.Add(item);
};
}
}
return data;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return null;
}
}
Extension:
public static void SetValue<T>(this T _source, string _property_name, object _value)
{
_source.GetType().GetProperty(_property_name).SetValue(_source, _value);
}
I have a series of asynchronous functions that are cascaded, but when it finishes executing the last, it does not return the values to the previous ones.
This is where my first call is run. This is a WebAPI function and always comes to an end.
[HttpGet]
[Route("integracao/iniciar")]
public IHttpActionResult FazerIntegrar()
{
try
{
Integrar objIntegrar = new Integrar();
return Ok(objIntegrar.Integra());
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
so my function is in my library is called. Within my function I have a for executing only once. The flow is never resumed by it to continue the loop
public async Task<bool> Integra()
{
var files = Directory.GetFiles(#"C:\inetpub\wwwroot\Atendup\Arquivos\Backup\");
bool retorno = false;
if (files != null)
{
foreach (var item in files)
{
retorno = false;
using (StreamReader sr = new StreamReader(item))
{
if (sr != null)
{
while (sr.EndOfStream == false)
{
string line = await sr.ReadLineAsync();
string[] grupo = line.Split(new[] { "#*#" }, StringSplitOptions.None);
procData objProc = new procData();
objProc.proc = grupo[0];
objProc.name = JsonConvert.DeserializeObject<List<string>>(grupo[1]);
objProc.valor = JsonConvert.DeserializeObject<List<object>>(grupo[2]);
objProc.tipo = JsonConvert.DeserializeObject<List<Type>>(grupo[3]);
_context = new IntegrarRepository("online_pedidopizza");
retorno = await _context.IntegrarAsync(objProc);
//retorno = await _context.IntegrarAsync(objProc);
}
}
}
if (retorno == true)
{
await DeleteAsync(item);
}
}
}
return retorno;
}
I have a third function just to mediate with the repository
public async Task<bool> IntegrarAsync(procData objProc)
{
return await this.SendIntegrarAsync(objProc);
}
And finally, communication with the database, all code is executed correctly. Debugging you can get to the end of this fourth function but then the debug stop and does not go back to the beginning
protected async Task<bool> SendIntegrarAsync(procData parametro)
{
bool retorno = false;
using (SqlConnection conn = new SqlConnection(""))
{
using (SqlCommand cmd = new SqlCommand(parametro.proc, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
if (parametro != null)
{
for (int i = 0; i < parametro.name.Count; i++)
{
AdicionaParametro(cmd, parametro.name[i], parametro.valor[i], parametro.tipo[i]);
}
}
try
{
cmd.CommandTimeout = 300;
await conn.OpenAsync().ConfigureAwait(false);
var resultado = await cmd.ExecuteScalarAsync().ConfigureAwait(false);
if (resultado != null)
{
retorno = Convert.ToBoolean(resultado);
}
}
catch (Exception ex)
{
Logs objLog = new Logs()
{
metodo = MethodBase.GetCurrentMethod().Name,
classe = this.GetType().Name,
dados = parametro,
data = DateTime.Now,
mensagem = ex.Message,
exception = ex.InnerException == null ? "" : ex.InnerException.ToString()
};
objLog.Adiciona();
string name = DateTime.Now.ToBinary().ToString();
using (StreamWriter sw = new StreamWriter(#"C:\inetpub\wwwroot\Atendup\Arquivos\Backup\" + name + ".txt"))
{
string line = "";
line += parametro.proc + "#*#";
line += JsonConvert.SerializeObject(parametro.name) + "#*#";
line += JsonConvert.SerializeObject(parametro.valor) + "#*#";
line += JsonConvert.SerializeObject(parametro.tipo) + "#*#";
sw.WriteLine(line);
}
}
}
}
return retorno;
}
What should I have to do? Thanks
Your Web Api call is not async try changing it to:
[HttpGet]
[Route("integracao/iniciar")]
public async Task<IHttpActionResult> FazerIntegrar()
{
try
{
Integrar objIntegrar = new Integrar();
return Ok(await objIntegrar.Integra());
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
I tried to look through some links but didn't work for me but this is what I have:
[HttpGet]
public string GetTimes()
{
var varCheck = checkUser();
if (varCheck.Item1)
{
using (SqlConnection sc = new SqlConnection(connectionTest))
{
try
{
sc.Open();
using (SqlDataAdapter sda = new SqlDataAdapter("GetTheTimes", sc))
{
sda.SelectCommand.CommandType = CommandType.StoredProcedure;
sda.Fill(ds);
foreach (DataTable table in ds.Tables)
{
foreach (DataRow row in table.Rows)
{
listItems.Add(new DataCheck
{
var1 = row["var1"].ToString(),
var2 = row["var2"].ToString()
});
}
}
}
}
catch (SqlException sqe)
{
return "There was an error with retrieving the data, please try again later";
}
finally
{
sc.Close();
}
}
var jsonSerialier = new JavaScriptSerializer();
var json = jsonSerialier.Serialize(listItems);
return json;
}
else
{
return "Failed";
}
}
When the API is called it is returned with escape double quotes. How can I modify so it returns a pure Json Object.
Try this:
[HttpGet]
//to prevent conflict with HttpGet use inline namespacing
public System.Web.Mvc.JsonResult GetTimes()
{
return new System.Web.Mvc.JsonResult { Data = result };
}
In my data access layer when I want to serialize something into JSON and give it to the client I've been doing something like
using (var con = new SqlConnection(connectionString))
{
using (var cmd = new SqlCommand("spGetLengthsOfStay", con))
{
con.Open();
cmd.CommandType = System.Data.CommandType.StoredProcedure;
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
var los = new LOS();
los.VisitId = (int)rdr["VisitId"];
los.PatientId = (int)rdr["PatientId"];
los.Gender = (string)rdr["Gender"];
los.Age = (int)rdr["Age"];
los.Discharge = (string)rdr["Discharge"];
los.LengthOfStay = (int)rdr["LengthOfStay"];
losList.Add(los);
}
}
}
There are some instances where I need to query the database with a dynamically generated SQL query, so I don't always know the properties to create a single instance of the object, add it to a list, and return the list. What's the preferred method for getting the results from a SQL query back to the client all at one, without using a concrete type using .NET MVC?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Dynamic;
using Newtonsoft.Json;
// microsoft sqlserver
using System.Data.SqlClient;
// oracle
using Oracle.ManagedDataAccess.Client;
namespace InqdWeb
{
public class Dbio
{
//
public static class Consts
{
public const string msgname = "retmsg";
public const string valname = "retval";
public const string jsond = "{ }";
public const string jsonr = "{ \"" + msgname + "\": \"OK\" }";
}
//
//
// »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
// core functions
// »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
//
//
// with a "sql statement"
// and a connection id,
// prepare the actual sql to get data
// return the result as json
public static string sqljson
(string pi_sql
, string pi_conn
)
{
// empty data
var vd = Consts.jsond;
// success message
var vr = Consts.jsonr;
string msgout = "00";
var ld = new List<dynamic>();
ld = sqlmaster(pi_sql, pi_conn, out msgout);
//
if (msgout.Substring(0, 2) == "00") // not empty and no errors
{
vd = JsonConvert.SerializeObject(ld);
vr = Consts.jsonr.Replace("OK", "00");
}
if (msgout.Substring(0, 2) == "10") // empty and no errors
{
vr = Consts.jsonr.Replace("OK", "10");
}
if (msgout.Substring(1, 1) == "1") // error
{
vd = JsonConvert.SerializeObject(ld);
vr = Consts.jsonr.Replace("OK", msgout);
}
// return json with 2 collections: d with data, r with status and message
var vt = jsonmerge(vd, vr);
return vt;
}
//
//
//
// with a sql
// and a conn id
// return data as dynamic list
public static List<dynamic> sqlmaster
(string pi_sql
, string pi_conn
, out string po_msg
)
{
string sql = " ";
sql = pi_sql;
// result
po_msg = msgout;
// po_msg pos1 empty: 1 has rows: 0
// pos2 error: >0 no error: 0
// pos3... error message
return lista;
}
//
//
// with a sql statement
// and a connection string
// return the result on a dynamic list
// plus a string with
// pos1 error 0-ok 1-error
// pos2 list empty 0-ok 1-list is empty
// pos3... message return code from non-select or error message
public static List<dynamic> sqldo
(string pi_sql
, string pi_connstring
, out string msgout
)
{
// variables
string sql = pi_sql;
var lista = new List<dynamic>();
int retcode;
msgout = "0";
//
string ConnString = pi_connstring;
//
//
//
// Microsoft SqlServer
if (SqlFlavor == "Ms")
{
using (SqlConnection con = new SqlConnection(ConnString))
{
try
{
con.Open();
SqlCommand cmd = new SqlCommand(sql, con);
if (sqltype == "R")
{
SqlDataReader reada = cmd.ExecuteReader();
string datatype = "-";
string colname = "-";
while (reada.Read())
{
var obj = new ExpandoObject();
var d = obj as IDictionary<String, object>;
//
for (int index = 0; index < reada.FieldCount; index++)
{
datatype = reada.GetDataTypeName(index);
colname = reada.GetName(index);
bool isnul = reada.IsDBNull(index);
if (!isnul)
{
// add datatypes as needed
switch (datatype)
{
case "int":
d[colname] = reada.GetValue(index);
break;
case "varchar":
d[colname] = reada.GetString(index);
break;
case "nvarchar":
d[colname] = reada.GetString(index);
break;
case "date":
d[colname] = reada.GetDateTime(index);
break;
default:
d[colname] = reada.GetString(index);
break;
}
}
else
{
d[colname] = "";
}
}
lista.Add(obj);
}
reada.Close();
}
}
catch (Exception ex)
{
msgout = "11" + ex.Message.ToString();
}
}
}
//
// Oracle
if (SqlFlavor == "Oa")
{
// Or uses a "
sql = sql.Replace("[", "\"");
sql = sql.Replace("]", "\"");
using (OracleConnection con = new OracleConnection(ConnString))
{
try
{
con.Open();
//
OracleCommand cmd = new OracleCommand(sql, con);
OracleDataReader reada = cmd.ExecuteReader();
string datatype = "-";
string colname = "-";
while (reada.Read())
{
var obj = new ExpandoObject();
var d = obj as IDictionary<String, object>;
// browse every column
for (int index = 0; index < reada.FieldCount; index++)
{
datatype = reada.GetDataTypeName(index);
colname = reada.GetName(index);
bool isnul = reada.IsDBNull(index);
if (!isnul)
{
// add datatypes as needed
switch (datatype)
{
case "Decimal":
d[colname] = reada.GetValue(index);
break;
case "Varchar":
d[colname] = reada.GetString(index);
break;
default:
d[colname] = reada.GetString(index);
break;
}
}
else
{
d[colname] = "";
}
}
lista.Add(obj);
}
reada.Close();
//
}
catch (Exception ex)
{
msgout = "11" + ex.Message.ToString();
}
}
}
//
//
//
return lista;
}
//
//
}
Use it in your controller
string vret = "{'r':{'retval': 'OK' }}";
string sqltxt;
string connt;
connt = ConfigurationManager.ConnectionStrings["<your connection>"].ConnectionString;
sqltxt = "<your select>";
vret = Dbio.sqljson(sqltxt, connt, "MsX"); // MsX for MsSqlServer
return Content(vret, "application/json");
I'm stuck on trying to work out how to solve the error above, how can i assign the value to recordsReturned which is an output parameter from the database and add it to ObjectCache.
Before the data is cached I can get the value, but I cannot add it to the cache, i have tried out and ref, but with no luck.
Hopefully someone with more experience than me can help with my problem.
I've added my code below:
public class RetrieveTravelGuideForSearchResults : IRetrieveTravelGuideForSearchResults
{
private readonly string _dbConn;
public RetrieveTravelGuideForSearchResults()
{
_dbConn = ConfigurationManager.ConnectionStrings["ADO_DBConn"].ConnectionString;
}
public IEnumerable<DisplayTravelGuideForSearchResults> DisplayTravelGuideSearchResults(string id,out int recordsReturned)
{
string cacheData = "DisplayTravelGuideSearchResults" + RegexHelpers.RegexRemoveAllInvalidCharactersAndSpace(id.ToLower());
ObjectCache travelGuideCache = MemoryCache.Default;
var objectInCache = travelGuideCache.Get(cacheData) as IEnumerable<DisplayTravelGuideForSearchResults>;
//recordsReturned = 0;
if (objectInCache != null)
{
recordsReturned = 0; //How can I get value from output parameter and add it here
return objectInCache;
}
const string spName = "dbo.spFTSTravelGuide";
//recordsReturned = 0;
using (var cn = new SqlConnection(_dbConn))
{
using (var cmd = new SqlCommand(spName, cn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#SearchPhrase", SqlDbType.VarChar, 100));
cmd.Parameters["#SearchPhrase"].Value = id;
cmd.Parameters.Add(new SqlParameter("#RecordsReturn", SqlDbType.Int));
cmd.Parameters["#RecordsReturn"].Direction = ParameterDirection.Output;
var data = new List<DisplayTravelGuideForSearchResults>();
try
{
cn.Open();
using (var rdr = cmd.ExecuteReader(CommandBehavior.Default))
{
if (rdr.HasRows)
{
while (rdr.Read())
{
data.Add(new DisplayTravelGuideForSearchResults
{
Country = (string)rdr["TravelGuideCountry"],
Description = RegexHelpers.RegexRemoveHtmlTags((string)rdr["TravelGuideDescription"])
});
}
}
}
var policy = new CacheItemPolicy { AbsoluteExpiration = DateTime.Now.AddMinutes(15) };
travelGuideCache.Add(cacheData, data, policy);
recordsReturned = cmd.Parameters["#RecordsReturn"].Value as int? ?? 0;
return data;
}
catch (SqlException ex)
{
throw new ApplicationException(ex.InnerException.ToString());
}
catch (Exception ex)
{
throw new ApplicationException(ex.InnerException.ToString());
}
}
}
}
}
have got the answer to my problem, should have done
recordsReturned = cmd.Parameters["#RecordsReturn"].Value as int? ?? 0;
travelGuideCache.Add("recordsReturned", recordsReturned, policy);
and then
if (objectInCache != null)
{
recordsReturned = travelGuideCache.Get("recordsReturned") as int? ?? 0;
return objectInCache;
}
This now get the output parameter value and allows me to cache it.