First of all my codes:
ManageClass.cshtml:
#{
ViewData["Title"] = "Class' Management";
}
<br />
<h2>Add Class</h2>
<form method="post" asp-controller="AddClassDB" asp-action="">
<div class="container">
<div class="form-group">
</div> </div>
<label for="formGroupExampleInput2">Class Name</label>
<input type="text" class="form-control" id="classNameInput">
<br/>
<div class="float-right">
<button type="submit" class="btn btn-success">Add</button>
</div>
<br />
<h2>Manage Class</h2>
</form>
HomeController.cs:
using Microsoft.AspNetCore.Mvc;
using StudentWeb.Models;
using System.Diagnostics;
namespace StudentWeb.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
public ActionResult ManageClass()
{
return View();
}
public ActionResult AddClassDB(ClassTable _table)
{
Console.WriteLine(_table);
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
I will take the value of classNameInput in ManageClass.cshtml and save it to SQL. I will do the saving in the Controller, but I have not yet received the value entered by the user.
But after I enter the value in the input and press the submit button, I get the following result:
(page not found)
You are using the wrong value for asp-controller and asp-action for the form. Hence it generates the wrong action path for the form.
It should be:
<form method="post" asp-controller="Home" asp-action="AddClassDB">
...
</form>
By default, all the action methods in the controller are GET (method). You need to apply [HttpPost] attribute so that the AddClassDB is recognized as POST (method).
[HttpPost("AddClassDB")]
public ActionResult AddClassDB(ClassTable _table)
{
Console.WriteLine(_table);
// TO-DO Redirect to view that is existed
return View();
}
Related
i'm making a webbapplication with ASP.NET MVC and im trying to edit my list of objects. If i for example add a product to the site and then click on edit for that product to change the prize i just get a new object with the new prize instead of changing the prize to the product.
So the problem is that instead of updating the products it just adds a new one.
this is how my controller for the products looks like:
using auktioner_MarcusR91.Data;
using auktioner_MarcusR91.Models;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace auktioner_MarcusR91.Controllers
{
public class InventoryController : Controller
{
private readonly AppDbContext _db;
public InventoryController(AppDbContext db)
{
_db = db;
}
public IActionResult Index()
{
IEnumerable<Inventory> objInventoryList = _db.Inventories;
return View(objInventoryList);
}
//GET
public IActionResult Create()
{
return View();
}
//Post
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Inventory inventory)
{
_db.Inventories.Add(inventory);
_db.SaveChanges();
return RedirectToAction("index");
}
//GET
public IActionResult Edit(int? id)
{
if (id == 0 || id == 5)
{
return NotFound();
}
var inventoryFromDb = _db.Inventories.Find(id);
if (inventoryFromDb == null)
{
return NotFound();
}
return View(inventoryFromDb);
}
//Post
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(Inventory inventory)
{
if (ModelState.IsValid)
{
_db.Inventories.Update(inventory);
_db.SaveChanges();
return RedirectToAction("index");
}
return View(inventory);
}
}
}
I think there is something wrong in my controller.
However here is also my view for when i edit a product:
#model Inventory
<form method = "post" asp-action = "Edit">
<div class = "border p-3 mt-4">
<div class = "row pb-2">
<h2 class = "text-primary">Edit Inventory</h2>
<hr />
</div>
<div class = "mb-3">
<label asp-for ="inventoryName"></label>
<input asp-for = "inventoryName" />
<label asp-for ="finalPrize"></label>
<input asp-for = "finalPrize" />
<label asp-for ="inventoryDesc"></label>
<input asp-for = "inventoryDesc" />
<p>1 för "Transport</p>
<p>2 för "Smycken"</p>
<p>3 för "Hushåll"</p>
<p>4 för "Dekoration"</p>
<select asp-for = "categoryId">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
</select>
</div>
<button type = "submit" class = "btn btn-primary" width = "100px">Update</button>
<a asp-controller = "Inventory" asp-action = "index" class = "btn btn-secondary" style = "width: 100px">Back to products</a>
</div>
</form>
You have to add a primary key inventoryId as a hidden input, without this key , you inventory instance looks like a new one for EF.
And since you are using [ValidateAntiForgeryToken] in the action, add this to view with another form syntax
#using (Html.BeginForm("Edit", "Inventory", FormMethod.Post))
{
#Html.AntiForgeryToken()
<input type="hidden" asp-for="inventoryId" value="#Model.inventoryId" />
....
<button type = "submit" class = "btn btn-primary" width = "100px">Update</button>
<a asp-controller = "Inventory" asp-action = "index" class = "btn btn-secondary" style = "width: 100px">Back to products</a>
</div>
}
and IMHO your update code could be like this
if (ModelState.IsValid)
{
var inventoryFromDb = _db.Inventories.Find(inventory.inventoryId);
if (inventoryFromDb == null)
{
return NotFound();
}
_db.Entry(inventoryFromDb).CurrentValues.SetValues(inventory);
var result= _db.SaveChanges();
}
You have to send your record id to the controller by clicking update button of the record . something like this :
<a class="btn btn-warning btn-sm btn-margin" asp-controller="ContextController" asp-action="UpdateAction" ***asp-route-id="#item.Id***">Update</a>
which #item is the object of the model sent to the view .
And the action would be :
[HttpGet]
public IActionResult UpdateAction(int id)
{
Model record = _Context.GetById(id);
return View("UpdateFormPageOrModal",record);
}
And after updating the form and clicking the submit button of the view data will send to action :
[HttpPost]
public IActionResult UpdateAction(Model record)
{
var result = _Context.UpdateBy(record);
ViewData["Result"] = result.Message;
if (result.IsSucceeded)
{
_UnitOfWork.Save();
return RedirectToAction("TheGridView");
}
return View("UpdateView",record);
}
where UpdateBy() method should be like this :
public void UpdateBy(T entity)//entity is an object of the DbSet<Model>
{
var state = _Context.Entry(entity).State;
if (state == EntityState.Detached)
{
_Context.Attach(entity);
}
_Context.Entry(entity).State = EntityState.Modified;
}
Trying to display authenticated user data in an MVC view.
Using ASP.NET Core 2.1
The following error occours:
An unhandled exception occurred while processing the request.
NullReferenceException: Object reference not set to an instance of an object.
AspNetCore.Views_Home_Index.ExecuteAsync() in Index.cshtml, line 6
There seems to be a problem with using #Model.id. What is the correct way of accessing properties of an authenticated user from within the view?
Models/LoginModel.cs
using Microsoft.AspNetCore.Identity;
namespace MyProject.Models
{
public class LoginModel
{
[Required]
[UIHint("email")]
public string Email { get; set; }
[Required]
[UIHint("password")]
public string Password { get; set; }
}
}
Views/Account/Login.cshtml
#model LoginModel
<h1>Login</h1>
<div class="text-danger" asp-validation-summary="All"></div>
<form asp-controller="Account" asp-action="Login" method="post">
<input type="hidden" name="returnUrl" value="#ViewBag.returnUrl" />
<div class="form-group">
<label asp-for="Email"></label>
<input asp-for="Email" class="form-control" />
</div>
<div class="form-group">
<label asp-for="Password"></label>
<input asp-for="Password" class="form-control" />
</div>
<button class="btn btn-primary" type="submit">Login</button>
</form>
Controllers/AccountController.cs
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginModel details, string returnUrl)
{
ApplicationUser user = new ApplicationUser();
if (ModelState.IsValid)
{
user = await userManager.FindByEmailAsync(details.Email);
if (user != null)
{
await signInManager.SignOutAsync();
Microsoft.AspNetCore.Identity.SignInResult result =
await signInManager.PasswordSignInAsync(
user, details.Password, false, false);
if (result.Succeeded)
{
return Redirect(returnUrl ?? "/");
}
}
ModelState.AddModelError(nameof(LoginModel.Email),
"Invalid user or password");
}
return View(details);
}
Views/Home/Index.cshtml
#model ApplicationUser
#if (User.Identity.IsAuthenticated)
{
#Model.Id
}
You can inject the UserManager into the view, and achieve the same result without having the pass a model into the view:
#using Microsoft.AspNetCore.Identity
#inject UserManager<ApplicationUser> UserManager
And then doing:
#await UserManager.GetUserIdAsync(User)
Trying to understand why my page doesn't work as expected. I was expecting the SignIn method on the controller to be called when clicking submit button, however, StartGame is still be called instead. The page originates through this URL: http://{domain}/Play/StartGame
Markup:
#{
ViewBag.Title = "Start Game";
}
<h2>StartGame</h2>
#using (Html.BeginForm())
{
#Html.TextBox("gamerId");
<input type="submit" value="SignIn" class="btn btn-default" />
}
Controller:
public class PlayController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult StartGame()
{
return View();
}
public ActionResult SignIn(string gamerId)
{
return View();
}
}
What am I missing here?
You need to specify the action in your BeginForm().
#using (Html.BeginForm("SignIn","Play"))
{
#Html.TextBox("gamerId");
<input type="submit" value="SignIn" class="btn btn-default" />
}
Or another option is to create an overload action and use an attribute:
[HttpPost]
public ActionResult StartGame(string gamerId)
{
return View();
}
This is my form
#using (Html.BeginForm("EditPayments", "BookingPathLabelsCms"))
{
if (#Model.DisplayName == "Payment Labels")
{
<textarea id="seeit" name="seeit" rows="5" cols="10"></textarea>
<textarea id="seeitNoSelect" name="seeitNoSelect" rows="5" cols="10"></textarea>
<div class="cmsButtonContainer">
Cancel it
<input type="submit" name="Save" value="Save it"#* onmouseover="copyto();"*# />
</div>
}
}
And this is my controller action
public ActionResult EditPayments(BookingPathLabelsCmsViewModel model)
{
string txtarea = Request.Form["seeit"];
return RedirectToAction("Index");
}
Am not getting the values of textareas here,but values in the breakpoint ,see image.
Your code should looks like:
#using (Html.BeginForm("EditPayments", "BookingPathLabelsCms"))
{
if (#Model.DisplayName == "Payment Labels")
{
#Html.TextBoxFor(m => m.SeeIt)
#Html.TextBoxFor(m => m.SeeItNoSelect)
<div class="cmsButtonContainer">
Cancel it
<input type="submit" name="Save" value="Save it"#* onmouseover="copyto();"*# />
</div>
}
}
Of course, your ViewModel BookingPathLabelsCmsViewModel should have SeeIt and SeeItNoSelect properties. After that, MVC will bind correctly entered data.
First create a class with property.
public class TextAreaProperty
{
public string MyTextAreaValue { get; set; }
}
Use on the view declare like:
#model <project_name>.Models.<Class_name>
In this case:
#model MvcApplication1.Models.TextAreaProperty
Use this textArea Razor
#Html.TextAreaFor(x=> x.MyTextAreaValue)
On method post receiving parameter type TextAreaProperty
[HttpPost]
public ActionResult Index(TextAreaProperty textAreaProperty)
{
return View();
}
You will get the value from textAreProperty.
From every page of a website I'm making, you're able to sign in. On pages with other forms, I get the following error after submitting: "Child actions are not allowed to perform redirect actions." All forms worked fine until I added the Sign In. In addition, the Sign In works correctly when you use it. The error only appears if I submit a different form. I've set a breakpoint and I've watched what happens when I hit the other submit. For some reason, the SignIn Post ActionResult is trying to run.
Any help would be appreciated.
Error:
Child actions are not allowed to perform redirect actions. Line 67: #{Html.RenderAction("SignIn", "Account");}
Sign In View
#using (Html.BeginForm("SignIn", "Account", FormMethod.Post))
{
<input class="signInSubmit" type="submit" name="submitButton" value="" />
}
Another Form in View
#using (Html.BeginForm("Confirm", "Cart", null, FormMethod.Post, new { #id = "productDetailsForm" }))
{
<input class="addToCart" type="submit" name="submit" value="" />
}
Sign In Controller
// GET: /Account/SignIn
public ActionResult SignIn()
{
return PartialView();
}
// POST: /Account/SignIn
[HttpPost]
public ActionResult SignIn(Customer customer)
{
try
{
//Stuff is here
return RedirectToAction("Index", "Home");
}
catch
{
return RedirectToAction("Registration");
}
}
Other form Controller
// GET: /Cart/
public ActionResult Index()
{
CartViewModel cart = getCart();
return View(cart);
}
//POST: Cart/Confirm
[HttpPost]
public ActionResult Confirm(int productID, bool certs, int quantity)
{
CartItemViewModel viewModel = new CartItemViewModel
{
Item = productRep.GetProductByID(productID),
Certs = certs,
Quantity = quantity
};
return View(viewModel);
}
HTML Source Code
<form action="/Account/SignIn" method="post">
<input class="signInSubmit" type="submit" value="" />
</form>
<form action="/Cart/Confirm" id="productDetailsForm" method="post">
<input class="addToCart" type="submit" value="" />
</form>
My solution
I renamed the POST ActionResult to anything other than SignIn. Does anyone understand why this works?
AccountController
// POST: /Account/Signed
[HttpPost]
public ActionResult Signed(Customer customer)
{
try
{
//Stuff is here
return RedirectToAction("Index", "Home");
}
catch
{
return RedirectToAction("Registration");
}
}