I am facing a bit of problem editing and deleting rows from SQL in ASP.NET MVC. The main problem I am facing is the fetch the QueryString value from url in my controller.
I can't attach Request.QueryString["Username"] for some reason. It is giving me Can not apply indexing with [] to an expression of type QueryString error.
Is there something I am doing it wrong or is there any way I can pass the QueryParameter through my controller to my Data access layer, where it will execute the desired query.
I am having the same problem with both Edit and Delete
This is my code looks like so far:
ShowUsers.cshtml (Edit and Delete actions are hooked up here)
@model IEnumerable<SecureMedi.Models.Users>
<section id="users">
<table id="users-table" class="table table-bordered table-responsive">
<thead>
<tr>
<th class="sort">Username</th>
<th class="sort">Role</th>
<th class="sort"><i class="md-icon dp18">mode_edit</i></th>
<th class="sort"><i class="md-icon dp18">delete</i></th>
</tr>
</thead>
<tbody class="list">
@foreach (var item in Model) {
<tr>
<td class="username">@item.Username</td>
<td class="role">@item.Role</td>
<td class="actions">@Html.ActionLink("Edit", "EditUser", "Home", new { Username = @item.Username }, null)</td>
<td class="actions">@Html.ActionLink("Delete", "DeleteUser", "Home", new { Username = @item.Username }, null)</td>
</tr>
}
</tbody>
</table>
</section>
EditUser.cshtml (For Editing) - Note: Here I would also like to display the Username value by default from the QueryString (Username=somename) in the form when the page loads. When going to EditUser action from ShowUsers page the url looks something like /Home/EditUser?Username=somename.
@model SecureMedi.Models.Users
<section id="edit-user">
<h4 class="sub-title space-top space-bottom">Edit user</h4>
<form id="edit-user-form" asp-controller="Home" asp-action="EditUser" method="post">
<div class="form-group">
<label asp-for="Username" class="form-control-label">Username</label>
<input asp-for="Username" type="text" class="form-control" id="username" name="Username" required disabled value="" />
</div><!-- / form-group -->
<div class="form-group">
<label asp-for="Role">Role</label>
<select asp-for="Role" class="form-control selector" id="role" name="Role" required>
<option value="" selected disabled>Select role</option>
<option value="SecureMediUsers">SecureMediUsers</option>
<option value="SecureMediModerators">SecureMediModerators</option>
<option value="SecureMediAdministrators">SecureMediAdministrators</option>
</select>
</div><!-- / form-group -->
<button type="submit" class="btn btn-primary">Save</button>
</form><!-- / form -->
</section>
HomeController.cs
[HttpGet]
public IActionResult EditUser() {
var model = new Users();
return View(model);
}
[HttpPost]
public IActionResult EditUser(Users u) {
if (!ModelState.IsValid) {
return View(u);
}
UsersDAL ud = new UsersDAL();
ud.Edit(u);
return RedirectToAction("ShowUsers");
}
[HttpPost]
public IActionResult DeleteUser(Users u) {
if (!ModelState.IsValid) {
return View(u);
}
UsersDAL ud = new UsersDAL();
ud.Delete(u);
return RedirectToAction("ShowUsers");
}
UsersDAL.cs (Data access layer)
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using SecureMedi.Models;
namespace SecureMedi.DAL {
public class UsersDAL {
public void Edit(Users u) {
string connectionstring = "MY_CONNECTION_STRING";
string sql = String.Format("ALTER ROLE {0} DROP MEMBER {1}", u.Role, u.Username);
string sql2 = String.Format("ALTER ROLE {0} ADD MEMBER {1}", u.Role, u.Username);
SqlConnection conn = new SqlConnection(connectionstring);
SqlCommand cmd = new SqlCommand(sql, conn);
SqlCommand cmd2 = new SqlCommand(sql2, conn);
try {
conn.Open();
using(conn) {
cmd.Transaction = conn.BeginTransaction();
cmd.ExecuteNonQuery();
cmd2.Transaction = cmd.Transaction;
cmd2.ExecuteNonQuery();
cmd2.Transaction.Commit();
}
} finally {
if (conn != null) {
conn.Close();
}
}
}
public void Delete(Users u) {
string connectionstring = "MY_CONNECTION_STRING";
string sql = String.Format("DROP USER {0}", u.Username);
SqlConnection conn = new SqlConnection(connectionstring);
SqlCommand cmd = new SqlCommand(sql, conn);
try {
conn.Open();
using(conn) {
cmd.ExecuteNonQuery();
}
} finally {
if (conn != null) {
conn.Close();
}
}
}
}
}
Users.cs (Model)
using System.ComponentModel.DataAnnotations;
namespace SecureMedi.Models {
public class Users {
[Required]
[StringLength(100)]
public string Username {
get;
set;
}
[Required]
[StringLength(100)]
public string Role {
get;
set;
}
}
}
In summary, the problems I am trying to solve are:
1) Passing the Username query param from EditUser view and Role value from the form to my EditUser controller function.
2) I have hooked up the delete action like
<td class="actions">@Html.ActionLink("Delete", "DeleteUser", "Home", new { Username = @item.Username }, null)</td>
But I'm confused on to how to avoid the [HttpGet] for DeleteUser action. When I click on the anchor tag it is taking me to /Home/DeleteUser?Username=somename, but instead I would just like to execute the DeleteUser action without the view change.
Also, how do I pass Username query param to the controller action.
u, the instance ofUserswhich is created from the data posted back in your form? The username passed in the original query parameter (which is gone when you post back) should be the same as the one submitted via the form. However, you disabled the controls, and disabled form controls are not submitted - you should just use a hidden field instead for this. You can display the username with @Model.Username