I have following controller:
public ActionResult delete(int id)
{
//call function
return RedirectToAction("Index");
}
here I want to call following function from my model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MySql.Data.MySqlClient;
namespace project1.Models.Admin
{
public class delete
{
public void delete(int id)
{
//xxx
const string ConnStr = "...";
MySqlConnection connection = new MySqlConnection(ConnStr);
connection.Open();
MySqlCommand sqlcmd2;
sqlcmd2 = connection.CreateCommand();
sqlcmd2.CommandText = "UPDATE `user` SET Aktive = 0 WHERE Nr = #id;";
sqlcmd2.Parameters.Add("#id", MySqlDbType.Int32).Value = id;
sqlcmd2.ExecuteNonQuery();
connection.Close();
//xxx
}
}
}
I get the error that "void" isn't allowed in this context. Is there any other way to call my function here or should I put the whole connection (inside "xxx") into my controller?
Change method name;
public void deleteFunc(int id)
EDIT
Firstly, you should be careful about naming convention. I change your class name like DeleteAction and method name DeleteRecord
public class DeleteAction
{
public void DeleteRecord(int id)
{
//xxx
const string ConnStr = "...";
MySqlConnection connection = new MySqlConnection(ConnStr);
connection.Open();
MySqlCommand sqlcmd2;
sqlcmd2 = connection.CreateCommand();
sqlcmd2.CommandText = "UPDATE `user` SET Aktive = 0 WHERE Nr = #id;";
sqlcmd2.Parameters.Add("#id", MySqlDbType.Int32).Value = id;
sqlcmd2.ExecuteNonQuery();
connection.Close();
//xxx
}
}
Then, you can call desired function by creating an instance from class;
public ActionResult delete(int id)
{
var deleteActionObject = new DeleteAction();
deleteActionObject.DeleteRecord(id);
return RedirectToAction("Index");
}
There are several problems in your code.
First you cannot use delete as both a class- and a member-name. Having said this delete is a really bad name for a class.
Second you should follow naming-conventions, e.g. use PascalCase-names for both methods and classes.
And last and most important, you need an instance of your class of which you want to call the method:
public ActionResult delete(int id)
{
myInstanceOfDeleteClass.delete(id);
return RedirectToAction("Index");
}
If you don´t have an instance of that class, you may also make delete a static one. Then you could directly call the method within your controller:
public ActionResult delete(int id)
{
DeleteClass.Delete(id);
return RedirectToAction("Index");
}
public class DeleteClass
{
public static void Delete(int id)
{
//xxx
const string ConnStr = "...";
MySqlConnection connection = new MySqlConnection(ConnStr);
connection.Open();
MySqlCommand sqlcmd2;
sqlcmd2 = connection.CreateCommand();
sqlcmd2.CommandText = "UPDATE `user` SET Aktive = 0 WHERE Nr = #id;";
sqlcmd2.Parameters.Add("#id", MySqlDbType.Int32).Value = id;
sqlcmd2.ExecuteNonQuery();
connection.Close();
//xxx
}
}
Related
My problem with my is to be able to retrieve the returned value (the name of the fund chosen by the user) by the post method in order to use it in my get method. this value will be the name of my ConnectionName
ConnectionName :
{
"ConnectionStrings": {
"DefaultConnection": "Server=.\\SQLEXPRESS; Database=Ctisn; Trusted_Connection=True; MultipleActiveResultSets=True;",
"MECLESINE": "Server=myserver; Database=aicha_meclesine; User ID=***; Password=***;",
"FONEES": "Server=myserver; Database=aicha_fonees; User ID=***; Password=***;",
"MECFP": "Server=myserver; Database=aaicha_mecfp; User ID=***; Password=***;",
"MECCT": "Server=myserver; Database=aicha_ct; User ID=***; Password=***;",
"JSR": "Server=myserver; Database=aicha_jsr; User ID=***; Password=***;",
}
Post and Get Methods :
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class TopClientsController : ControllerBase
{
private readonly IConfiguration \_configuration;
public TopClientsController(IConfiguration configuration)
{
_configuration = configuration;
}
[HttpPost("{AdminValue}")]
public JsonResult Post(string AdminValue)
{
return new JsonResult(new { data = AdminValue });
}
[HttpGet]
public JsonResult Get()
{
string query = #"
-------------------My sql requet-----------------
";
var iden;
if (User.IsInRole("Administrator"))
{
// iden = The result of the post methode ;
}
else
{
iden=((System.Security.Claims.ClaimsIdentity)User.Identity).FindFirst("caisse").Value;
}
DataTable table = new DataTable();
string sqlDataSource = _configuration.GetConnectionString($"{iden}");
MySqlDataReader myReader;
using (MySqlConnection mycon = new MySqlConnection(sqlDataSource))
{
mycon.Open();
using (MySqlCommand myCommand = new MySqlCommand(query, mycon))
{
myReader = myCommand.ExecuteReader();
table.Load(myReader);
myReader.Close();
mycon.Close();
}
}
return new JsonResult(table);
}
}
I don't know will you understand my idea, but the connection to the database depends on the fund the user belongs to and if it's the admin, he chooses the fund he wants to point to 'send to the API and I get this name I pass it to my get method.
You can't do what you're asking (or, rather, shouldn't). There's no guarantee in an API that someone will always do a POST before then calling a GET. What you can do is provide the parameter in the GET request. Ideally speaking, though, for anything concerning priviliges, you want to also add a password or other form of authentication to prevent abuse.
[HttpGet]
public JsonResult Get([FromUri] string admin)
{
}
The controller's action is a method. You can do a classic method call :
[HttpGet]
public JsonResult Get()
{
...
var postResult = Post("foo");
...
}
I am learning how to create webapi and I need some help. I'm having trouble building the post controller! I am not able to make it work directly in the method I created to add the values to the database. I can't find any help on the content I searched for, documentation and etc ... Any suggestions?
Class Model:
public class TbStudents
{
public int StuId { get; set; }
public string StuName { get; set; }
public string StuDegree { get; set; }
}
Class Method:
Post
public class MethodStudents
{
//GET Method
public async Task<List<TbStudents>> GetReadStudents()
{
List<TbStudents> list = new List<TbStudents>();
using (NpgsqlConnection myConn = new NpgsqlConnection(Conns.ConnStudents))
{
string sql = "SELECT * FROM students ORDER BY stu_name";
NpgsqlCommand myQuery = new NpgsqlCommand(sql, myConn);
myConn.Open();
NpgsqlDataReader myReader = await myQuery.ExecuteReaderAsync();
while (myReader.Read())
{
TbStudents data = new TbStudents
{
StuId = int.Parse(myReader["stu_id"].ToString()),
StuName = myReader["stu_name"].ToString(),
StuDegree = myReader["stu_degree"].ToString(),
};
list.Add(data);
}
myConn.Dispose();
}
return list;
}
//POST Method
public async Task addStudent(TbStudents student) {
using(NpgsqlConnection myConn = new NpgsqlConnection(Conns.ConnStudents)) {
string sql = "INSERT INTO students (stu_name, stu_degree)" +
"VALUES (#name, #degree)";
NpgsqlCommand myQuery = new NpgsqlCommand(sql, myConn);
myQuery.Parameters.AddWithValue("#name", students.StuName);
myQuery.Parameters.AddWithValue("#degree", students.StuDegree);
myConn.Open();
await myQuery.ExecuteNonQueryAsync();
myConn.Dispose();
}
}
}
Class Controllers:
{
[Route("api/[controller]")]
[ApiController]
public class StudentsController : ControllerBase
{
MethodStudents methodStudents = new methodStudents();
// GET: api/students
[HttpGet]
public async Task<ActionResult<List<TbStudents>>> GetStudents()
{
var list = methodStudents.GetReadStudents();
return await list;
}
//Post: api/students
[HttpPost]
public async Task<ActionResult<TbStudents>> PostStudents()
{
var postStu = methodStudents.AddStudents();
return await postStu;
}
}
}
The controller [HttpPost] is stuck me with some errors...
On the line: var postStu = methodStudents.AddStudents();
Error CS7036 There is no argument given that corresponds to the required formal parameter 'student' of 'MethodStudents.AddStudent(TbStudents)'
On the line: return await postStu;
Error CS0029 Cannot implicitly convert type 'void' to 'Microsoft.AspNetCore.Mvc.ActionResult<TestApiStudents.Data.Models.TbStudents>'
You need to be passing a value into the AddStudent() method when you call it at var postStu = AddStudent(); since you are defining the method with a parameter. Also, I am not sure if this is a typo, but in your PostStudents() method, you are calling .AddStudents(), you should remove the dot '.'
Here I write some code in static methode which is in class file please Help me how can i create instance of static class
public class ConnectionString
{
public static void CreateCommand(string querystring, string connectionString)
{
using(SqlConnection cn = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(querystring, cn);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
}
}
Just call it like this:
string querystring = "Your values here";
string connectionString = "Your values here";
ConnectionString.CreateCommand(querystring, connectionString);
That's it.
Your ConnectionString class can be refactored to implement an interface like this:
public interface IDataAccess
{
void CreateCommand(string querystring, string connectionString);
}
this interface allows us to inject its implementation in the controller that you mentioned in the comments. So your ConnectionString class (renamed to more meaningful name DataAccess) should look like this:
public class DataAccess : IDataAccess
{
public void CreateCommand(string querystring, string connectionString)
{
using (SqlConnection cn = new SqlConnection(connectionString))
{
cn.Open();
using (SqlCommand cmd = new SqlCommand(querystring, cn))
{
cmd.ExecuteNonQuery();
}
}
}
}
then in your controller / client class you can have the concrete implementation injected at the run time..
public class DataController : Controller
{
private readonly IDataAccess dataAccess;
public DataController(IDataAccess dataAcces)
{
this.dataAccess = dataAcces;
}
public ActionResult ShowData()
{
string querystring = "you t-sql query";
string connectionString = "<you sql connection string>";
this.dataAccess.CreateCommand(querystring, connectionString);
return this.View();
}
}
If you are using MVC and dont know how to resolve the dependencies then refer to this article
Alternatively you can just new up the instance of DataAccess class like this:
public class DataController : Controller
{
private readonly IDataAccess dataAccess;
public DataController()
{
this.dataAccess = new DataAccess();
}
public ActionResult ShowData()
{
string querystring = "you t-sql query";
string connectionString = "<you sql connection string>";
this.dataAccess.CreateCommand(querystring, connectionString);
return this.View();
}
}
I will not recommend this approach as it wont be possible to unit test it.
Hope this helps!
I’m newly to the ASP.NET MVC with Web API 2 and I created async and await method by using asp.net MVC with Web API 2 which is going to be store into the SQL DB. When I try to call my repository method in the API Controller I got an error cannot await ”system.collections.generic.list”. If anybody has idea about it kindly let me know.
Note:- I don’t want to use entity framework instead I want to store data through stored procedure.
Model:
namespace AsyncMVCWEBAPI.Models
{
public class Product
{
public string Name { get; set; }
public double Price { get; set; }
public string Category { get; set; }
}
}
API Controller:
public static async Task<Product> GetProduct()
{
return await GetAllProduct(); // Here i'm getting an error can not await "system.collections.generic.list"
}
Repository:
public static IEnumerable<Product> GetAllProduct()
{
using (SqlConnection con = new SqlConnection(connectionString))
{
if (con.State == ConnectionState.Closed)
con.Open();
List<Product> students = new List<Product>();
SqlCommand cmd = new SqlCommand("spGetAllStudentDetails", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Product product = new Product();
product.Price = Convert.ToInt32(rdr["Price"]);
product.Name = rdr["Name"].ToString();
product.Category = rdr["Category"].ToString();
students.Add(product);
}
return students;
}
}
The main problem is that you can't await a method that is not async. You should rewrite your GetAllProduct method to make it async with the following signature:
public static async Task<IEnumerable<Product>> GetAllProduct()
Also don't forget to use Async methods to get your data from database:
...
await con.OpenAsync();
...
SqlDataReader rdr = await cmd.ExecuteReaderAsync();
while (await rdr.ReadAsync())
{
...
students.Add(product);
}
return students;
As the previous answer said you have to change your signature to:
public static async Task<IEnumerable<Product>> GetAllProduct()
If you want to skip the ADO.NET boilerplate stuff, you can instead use Dapper (https://github.com/StackExchange/dapper-dot-net) to simplify the code:
public static async Task<IEnumerable<Product>> GetAllProduct()
{
using (var con = new SqlConnection(connectionString))
{
await con.OpenAsync();
return await con.QueryAsync<Product>("spGetAllStudentDetails", commandType: CommandType.StoredProcedure);
}
}
I have assigned the retrieved data (ChancesLeft) from the database, and assign it with the created variable. But when I check the created variable in the controller (which already assigned to the retrieved data (ChancesLeft) from the database, the value of created variable is always 0, even though I already called that retrieve function. But, when I check in the class which the retrieve function is, the value of created variable is not 0, but following the value of retrieved data (ChancesLeft).
My question is, how can I pass the value from the class to the controller? So that I can use it?
Code (SystemManager):
public void RetrieveChancesLeft(string Name)
{
MyModel context = new MyModel();
using (SqlConnection conn = new SqlConnection(connectionString))
{
string query = "SELECT [Name], [ChancesLeft] FROM [Credentials] WHERE [Name] = #Name";
conn.Open();
using (SqlCommand cmd = new SqlCommand(query, conn))
{
cmd.Parameters.Add("#Name", SqlDbType.NVarChar);
cmd.Parameters["#Name"].Value = Name;
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
context.Chances = Convert.ToInt32(reader["ChancesLeft"]);
}
}
}
conn.Close();
}
}
Controller:
SystemManager _sm = new SystemManager();
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(MyModel context, string Name)
{
_sm.RetrieveChancesLeft(Name);
if (context.Chances > 0)
{
return RedirectToAction("About", "Home");
}
else
{
return RedirectToAction("GetStarted", "Home");
}
}
The problem is, whenever I run the program and enter the Name it always redirect to the GetStarted View, so that means that context.Chances is always 0, even though the ChancesLeft in the database is not 0.
Your RetrieveChancesLeft function should store the local context object in your SystemManager object for retrieval or return the context to the caller. You can change the return type of your RetrieveChancesLeft function to get the object passed to the controller:
public MyModel RetrieveChancesLeft(string Name)
{
MyModel context = new MyModel();
using (SqlConnection conn = new SqlConnection(connectionString))
{
string query = "SELECT [Name], [ChancesLeft] FROM [Credentials] WHERE [Name] = #Name";
conn.Open();
using (SqlCommand cmd = new SqlCommand(query, conn))
{
cmd.Parameters.Add("#Name", SqlDbType.NVarChar);
cmd.Parameters["#Name"].Value = Name;
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
context.Chances = Convert.ToInt32(reader["ChancesLeft"]);
}
}
}
conn.Close();
}
return context;
}
And your controller:
SystemManager _sm = new SystemManager();
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(MyModel context, string Name)
{
context = _sm.RetrieveChancesLeft(Name);
if (context.Chances > 0)
{
return RedirectToAction("About", "Home");
}
else
{
return RedirectToAction("GetStarted", "Home");
}
}