I have a button that's supposed to run a SQL query.
<button class="btn btn-info mt-3"asp-controller="MessageCenter" asp-action="Markmessage">Mark</button>
there is no forms or any sort of thing that I can use a post method for. here is the function that I'm trying to call(this is in my controller by the way).
public void Markmessage()
{
Messagelookupinfo messagelookup = new Messagelookupinfo();
SqlConnection sql = new SqlConnection();
SqlConnection sqlcon = new SqlConnection("data source");
sqlcon.Open();
SqlCommand sqlcom = new SqlCommand("update messages set messagestatus='MARKED' where messageid=" + messagelookup.Messageid, sqlcon);
sqlcom.ExecuteNonQuery();
sqlcon.Close();
RedirectToAction("Messagelookup", "Messageid=" + messagelookup.Messageid);
}
There is no feedback/confirmation for the user just straight up run the query and reload the page.
How do I achieve this?
I made a simple example, you can refer to it.
View (Messagelookup.cshtml):
#{
ViewData["Title"] = "Messagelookup";
}
<h1>Messagelookup</h1>
<div>
<label>MessageId:</label>
<h2>#ViewBag.MessageId</h2>
</div>
<a class="btn btn-info mt-3" asp-controller="MessageCenter" asp-action="Markmessage" asp-route-messageid="2">Mark</a>
Controller:
public class MessageCenterController : Controller
{
public IActionResult Messagelookup(int? Messageid)
{
ViewBag.Messageid = Messageid;
return View();
}
public IActionResult Markmessage(int? messageid)
{
return RedirectToAction("Messagelookup", new { Messageid = messageid });
}
}
Result:
Related
Is there any Core 2.1 sample available for using SignalR with SQLDependency.
Did enable broker, etc. but never get any dependency onChange event firing. Just the event subscribe is triggered.
When the MS-SQL database table Cities changes on the back-end, I want to see the change reflected right-away on the client web page without having to refresh/reload the page.
//start the dependency when app start in ConfigureServices
SqlDependency.Start(Configuration.GetConnectionString("DefaultConnection"));
using Microsoft.AspNetCore.SignalR;
using SignalR_Test4.Data;
using SignalR_Test4.Hubs;
using System.Collections.Generic;
using System.Data.SqlClient;
namespace SignalR_Test4.Models
{
public class CityRepository
{
private readonly ApplicationDbContext _context;
private readonly IHubContext<CityHub> _hubcontext;
public CityRepository(ApplicationDbContext context, IHubContext<CityHub> hubcontext)
{
_context = context;
_hubcontext = hubcontext;
}
public IEnumerable<City> GetCities()
{
List<City> listOf = new List<City>();
//listOf = _context.Cities;
using (var conn = new SqlConnection(GlobalVar.connectionString))
{
conn.Open();
using (var cmd = new SqlCommand(#"SELECT * FROM Cities", conn))
{
cmd.Notification = null;
SqlDependency dependency = new SqlDependency(cmd);
dependency.OnChange += Dependency_OnChange;
if (conn.State == System.Data.ConnectionState.Closed)
conn.Open();
var reader = cmd.ExecuteReader();
while (reader.Read())
{
listOf.Add(new City { Id = (string)reader["Id"], Name_en = (string)reader["name_en"], CountryId = (string)reader["CountryId"], Code = (string)reader["Code"] });
}
}
}
return listOf;
}
private void Dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
_hubcontext.Clients.All.SendAsync("GetCities");
}
}
}
}
The issue was within the line:
var cmd = new SqlCommand(#"SELECT Id, Name_en, CountryId, Code from [dbo].Cities", conn)
It is required to use the field name (Not the *) and also the 2 part table name convention => [dbo].Cities
I have a view, where I'm calling an ActionResult method, but putting a breakpoint in the method tells me it's not being called.
<div>
<ul class="list-group">
#foreach (var item in Model)
{
<li class="list-group-item">
<h4>Slide ID: #item.SlideId</h4>
<p><i>Received: #item.TimeStamp</i></p>
<div class="row">
<div class="col-md-4">
<h4>#Html.ActionLink("View details", "Well", new {slideid = item.SlideId})</h4>
<img src="#Url.Action("Index", "Images", new {id = item.SlideId})"/> //This is where I want to call the method
</div>
</div>
</li>
}
</ul>
And here's the method:
public class ImagesController : Controller
{
// GET: Images
public ActionResult Index(string id)
{
byte[] imageData = new byte[0];
string cs = "Data Source=" + "some path";
using (SQLiteConnection con = new SQLiteConnection(cs))
{
string stm = "SELECT LastImage FROM Well WHERE SlideId = " + "'" + id + "'";
con.Open();
using (SQLiteCommand cmd = new SQLiteCommand(stm, con))
{
using (SQLiteDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
imageData = Serialize(rdr["LastImage"]);
}
rdr.Close();
}
}
con.Close();
}
return File(imageData, "image/png");
}
public static byte[] Serialize(object obj)
{
var binaryFormatter = new BinaryFormatter();
var ms = new MemoryStream();
binaryFormatter.Serialize(ms, obj);
return ms.ToArray();
}
}
What I'm trying to achieve with this code is to load in an image from the database into the view. Any hints as to what I'm doing wrong?
Now with RouteConfig:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
When you write <img src="#Url.Action("Index", "Images", new {id = item.SlideId})"/> you don't call the action but the route url. The result is a string, for example localhost:8080/images/index/abcd123456 so, if you want to call the action, you need to use #Html.Action("Index", "Images", new {id = item.SlideId}). Note #Html.Action instead of #Url.Action
I think instead of opening and closing a db connection for each image, a better approach would be to gather all the information to render that page and send it in the model of the view you posted. Say it's called Index action of HomeController. It would look like something like this:
public class HomeController : Controller
{
public ActionResult Index(string id)
{
var listOfItems = new List<SomeClass>();
string cs = "Data Source=" + "some path";
using (SQLiteConnection con = new SQLiteConnection(cs))
{
string stm = "SELECT SlideId, TimeStamp, LastImage FROM Well";
con.Open();
using (SQLiteCommand cmd = new SQLiteCommand(stm, con))
{
using (SQLiteDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
var someItem = new SomeClass()
{
SlideId = rdr["SlideId"],
ImageData = Serialize(rdr["LastImage"]),
TimeStamp = rdr["TimeStamp"]
};
listOfItems.Add(someItem);
}
rdr.Close();
}
}
con.Close();
}
return View(listOfItems);
}
}
Of course if there are too many items you should always consider paging and limit the number of items in the list to cut down the response times.
I want to return the view of Index action method in create action method.I tried writing return View("Index"); in Index action method but nothing happened.Both my action methods are in the same controller. How can I do that?
Code:
public class GuestbookController : Controller
{
// GET: /Guestbook/
public ActionResult Index()
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["GuestbookContext"].ToString());
string query = string.Format("Select * from Guestbook");
SqlCommand cmd = new SqlCommand(query, conn);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
List<GuestbookEntry> li = new List<GuestbookEntry>();
while (reader.Read())
{
GuestbookEntry GuestbookEntry = new GuestbookEntry();
GuestbookEntry.Name = Convert.ToString(reader["Name"]);
GuestbookEntry.Message = Convert.ToString(reader["Message"]);
GuestbookEntry.Id = Convert.ToInt32(reader["Id"]);
GuestbookEntry.DateAdded = Convert.ToDateTime(reader["DateAdded"]);
li.Add(GuestbookEntry);
}
conn.Close();
var mostRecentEntries =(from entry in li orderby entry.DateAdded descending select entry);
ViewBag.Entries = mostRecentEntries.ToList();
return View();
}
[HttpPost]
public ActionResult Create(GuestbookEntry entry)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["GuestbookContext"].ToString());
string query = string.Format("Insert into [Guestbook] values ('{0}','{1}','{2}')", entry.Name, entry.Message, DateTime.Now);
SqlCommand cmd = new SqlCommand(query, conn);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
return View("Index");
}
}
You are only using the view, and not the action, so the ViewBag you are filling, wont be available.
You can use use RedirectToAction() to redirect the current action to the other action.
[HttpPost]
public ActionResult Create(GuestbookEntry entry)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["GuestbookContext"].ToString());
string query = string.Format("Insert into [Guestbook] values ('{0}','{1}','{2}')", entry.Name, entry.Message, DateTime.Now);
SqlCommand cmd = new SqlCommand(query, conn);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
return RedirectToAction("Index");
}
If you are trying to return to the index page as if it was called from the client then you should use:
return Index(); //If you don't care about adjusting URL on client's machine
Or
RedirectToAction("Index") //If you want to update client's URL
Please note that the second option does entail a full round trip to the client and back to the server and can not be used easily in case of Ajax calls, while the first option "stays on the server" and can be used with Ajax.
I have a 2 textbox for username and password and a button. I want to allow authenticated users to login and redirect to another page and display welcome authenticated username.Or else display the message Invalid username.How to perform this using session and connect to database.How to configure with database. Please help me.
My code is
<div id="loginbox">
<div align="center" style="width: 100%;">
</div>--%>
<br />
<label for="username">Username:</label> <input type="text"
id="username" /></li>
<label for="password">Password:</label> <input type="password" id="password" />
<input type="button" runat="server" value="Login">
</form>
My .cs code
protected void btnLogin_onclick(object sender, EventArgs e)
{
string connect = "Data Source=ST0022;Initial Catalog=QuickMove_Globe;Persist
Security Info=True;User ID=sa;Password=good";
string query = "Select Count(*) From Common.Users Where UserID = ? And Password =
?";
int result = 0;
SqlConnection con= new SqlConnection(connect);
SqlCommand cmd = new SqlCommand(query, con);
cmd.Parameters.AddWithValue("UserID",username.Value);
cmd.Parameters.AddWithValue("Password", password.Value);
con.Open();
Session["User"] = username.Value;
result = (int)cmd.ExecuteScalar();
if (result > 0)
{
Response.Redirect("TestPortalPage.aspx");
}
else
{
lbluser.Text = "Invalid credentials";
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Security.Cryptography;
using System.Web.Security;
public partial class Account_Login : System.Web.UI.Page
{
SqlConnection conn = new SqlConnection ("Data Source=.\\SQLEXPRESS; AttachDbFilename=E:\\Raugh\\asp\\Login\\App_Data\\Database.mdf;Integrated Security=True;User Instance=True");
protected void Page_Load(object sender, EventArgs e)
{
}
protected void LoginButton_Click(object sender, EventArgs e) //click event of login button
{
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT u_id, u_pass from [user] where u_id = '"+UserName.Text+"' and u_pass='"+Password.Text+"'");
cmd.Connection = conn;
SqlDataAdapter da = new SqlDataAdapter(cmd.CommandText, conn);
SqlDataReader dr = cmd.ExecuteReader();
if (dr.Read() == true)
{
Session.Timeout = 1;
Response.Redirect("~/Default.aspx");
//Response.Write("<script Language='JavaScript'> alert('Logged In')</script>");
conn.Close();
}
else
{
Response.Write("<script Language='JavaScript'> alert('Log In Failed')</script>");
conn.Close();
}
}
}
This page might help put you on the right track.
Check this article
http://csharpdotnetfreak.blogspot.com/2012/06/login-page-form-example-in-aspnet.html
and passing username through sessions is simple
Session["User"] = username;
in the redirected page use this in what ever control you placed, for example if it is a label
if(Session["User"]!=null)
{
label1.Text=Session["User"].ToString();
}
// else
// {
// label1.Text="Invalid Username;
// }
else condition is not needed in your case as you will redirect when the credentials are matched.
your code should be
string strCon = "Data Source=ST0022;Initial Catalog=QuickMove_Globe;Persist
Security Info=True;User ID=sa;Password=good";
string strSelect = "SELECT COUNT(*) FROM youtablename WHERE yourcolumnname = #Username AND yourcolumnname = #Password";
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/