I am new to ASP.NET MVC and I'm trying to create a small project but I'm stuck in the Edit Controller part.
This is my "real" controller with a function named PostEditViewModel with the queries inside to change the data.
public EditViewModel PostEditViewModel(EditViewModel model)
{
//var model = new EditViewModel();
using (var db = new NorthwindEntities())
{
var dati = db.Products
.Where(p => p.Id == model.Id).Single();
dati.Id = model.Id;
dati.Name = model.Name;
db.SaveChanges();
return model;
}
}
And this is my controller, its function is to only validate the model state.
[HttpPost]
public ActionResult Edit(EditViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
return RedirectToAction("Index");
}
Any help would be appreciated.
My bad, the validation didn't make sense at all.
[HttpPost]
public ActionResult Edit(EditViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
else
{
WorkerServices.PostEditViewModel(model);
return RedirectToAction("Index");
}
Related
i am new in MVC5. I am trying to load master and details data using ActionResult for retrieving master data and JsonResult for Details retrieving data single click in ActionLink.
public JsonResult getOrderDetails(int? id)
{
List<OrderDetail> OrderDetail = new List<OrderDetail>();
OrderDetail = db.OrderDetails.Where(a => a.OrderID==id).OrderBy(a => a.OrderDetialsID).ToList();
return new JsonResult { Data = OrderDetail, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
OrderMaster OrderMaster = db.OrderMasters.Find(id);
return View(OrderMaster);
}
No, this won't work. It will throw an exception explaining that a link must point to exactly one resource (a.k.a one Controller, one Action). Also, that's not how you normally think of doing it in MVC. This is not WebForms where you load the master and detail separately.
You should be doing something like this instead:
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var orderMaster = db.OrderMasters
.Where(om => om.OrderMasterId == id)
.Include(om => om.OrderDetails) // include the details here
.Single();
return View(orderMaster);
}
I am trying to update a news post. The post has a date field called Created that is populated when the record is initially created. I don't include this when updating, so when using the below method, this is null and throws an error.
I am using MVC 5 and Entity Framework 6
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,Title,Summary,Content")] Post post) {
if (ModelState.IsValid) {
db.Entry(post).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(post);
}
This method does work but it seems a bit clunky.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,Title,Summary,Content")] Post post) {
if (ModelState.IsValid) {
var newsPost = db.Posts.Find(post.Id);
if (newsPost == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); }
newsPost.Title = post.Title;
newsPost.Summary = post.Summary;
newsPost.Content = post.Content;
db.Entry(newsPost).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(post);
}
What is the best practice method of doing this?
Thanks!
EF also has a simple built-in "AutoMapper" that works with scalar values.
public class PostViewModel()
{
public string Id {get;set;}
public string Title {get;set;}
public string Summary {get;set;}
public string Content {get;set;}
}
public ActionResult Edit(PostViewModel viewModel)
{
if (ModelState.IsValid) {
var newsPost = db.Posts.Find(post.Id);
...
db.Entry(newsPost).CurrentValues.SetValues(viewModel);
...
}
}
I use a repository method. Works really well.
It copies the column which are different. Sort of PATCH against PUT
public void CopyUpdate<T> (T modelorig, T model) where T : class
{
_context.Entry(model).CurrentValues.SetValues(modelorig);
_context.Set<T>().Add(model);
_context.Entry(model).State = EntityState.Modified;
_context.SaveChanges();
}
The "correct" way to do this, assuming you want to stick to Rest. Is to use HttpPatch.
https://learn.microsoft.com/en-us/aspnet/core/web-api/jsonpatch?view=aspnetcore-6.0
[HttpPatch]
[ValidateAntiForgeryToken]
public async Task<ActionResult> PatchAsync([FromBody] JsonPatchDocument<Post> patchDoc, int id) {
var post = db.Find(id);
patchDoc.ApplyTo(post, ModelState);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
await db.SaveChangesAsync();
return new ObjectResult(post);
}
Noob needs help!) How can I return an existing view from a new action within the same controller?
For example I have a following code:
[HttpGet]
public ActionResult Index()
{
return View(); //returns Index.cshtml
}
[HttpPost]
public ActionResult Index(string id, string condition)
{
SomeModel.ID = id;
SomeModel.Condition = condition;
return View(SomeModel); //returns Index.cshtml delegating the model
}
public ActionResult someAction()
{
return View(); //How to make this action return Index.cshtml??
}
You can specify the view name to return:
public ActionResult someAction()
{
return View("Index");
}
public ActionResult someAction()
{
return View("Index"); //How to make this action return Index.cshtml??
}
Just add
return View("YourView");
If you want send a model to it you can do this
var model = new YourViewModel
{
}
return View("YourView", model);
My page has a search box which for has a few radio buttons. Depending on which radio button is selected will depend on which view is shown.
However, I don't know how to return the View.
My code is
public ActionResult Index(string jobType)
{
if (jobType.ToLower() == "this")
CandidateResults();
else
JobResults();
}
private ActionResult CandidateResults()
{
var model = //logic
return View(model);
}
private ActionResult JobResults()
{
var model = //logic
return View(model);
}
But this displays nothing on screen (a white page). This makes sense but I don't want to return Index, I want to return a new page (called either JobResults or Candidates) and create a View for both of these new pages but when I right click in my methods (JobResults() or Candidates()) I don't get the option to Add View.
At this stage I'm lost, can any one please give advice.
Either return the view from Index or redirect to CandidateResults or JobResults actions.
public ActionResult Index(string jobType)
{
if (jobType.ToLower() == "this")
return CandidateResults();
else
return JobResults();
}
private ActionResult CandidateResults()
{
var model = //logic
return View(model);
}
private ActionResult JobResults()
{
var model = //logic
return View(model);
}
Try this
public ActionResult Index(string jobType)
{
return (jobType.ToLower() == "this") ?
RedirectToAction("CandidateResults") :
RedirectToAction("JobResults");
}
private ActionResult CandidateResults()
{
var model = //logic
return View(model);
}
private ActionResult JobResults()
{
var model = //logic
return View(model);
}
In your private methods you have to specify the actual view you want to display.
public ActionResult Index(string jobType)
{
if (jobType.ToLower() == "this")
CandidateResults();
else
JobResults();
}
private ActionResult CandidateResults()
{
var model = //logic
return View("CandidateResults", model);
}
private ActionResult JobResults()
{
var model = //logic
return View("JobResults", model);
}
This happens because of the way the view engine works. The action name for the current request is always Index when the index function is called. Even if you call another method, the view engine will use the name of the current action and not the name of the currently executing function.
Just you need to redirect the user to proper controller method and that method will return its View as below:
public ActionResult Index(string jobType)
{
if (jobType.ToLower() == "this")
return RedirectToAction("CandidateResults","ControllerName");
else
return RedirectToAction("JobResults","ControllerName");
}
public ActionResult Index(string jobType)
{
if (jobType.ToLower() == "this")
return RedirectToAction("CandidateResults");
return RedirectToAction("JobResults");
}
private ActionResult CandidateResults()
{
var model = //logic
return View(model);
}
private ActionResult JobResults()
{
var model = //logic
return View(model);
}
I'm having trouble when handling the Post request for my controller:
[HttpGet]
public ActionResult Crear()
{
CarreraRepository carreraRepository = new CarreraRepository();
var carreras = carreraRepository.FindAll().OrderBy(x => x.Nombre);
var carrerasList = new SelectList(carreras, "ID", "Nombre");
ViewData["Carreras"] = carrerasList;
Materia materia = new Materia();
return View(materia);
}
[HttpPost]
public ActionResult Crear(Materia materia, FormCollection values)
{
if (ModelState.IsValid)
{
repo.Add(materia);
repo.Save();
return RedirectToAction("Index");
}
return View(materia);
}
When the HttpGet action runs, the form to create renders fine. The values are set correctly on the DropDownList and everything is peachy; when I try to submit the form (run the HttpPost action) I receive the error.
Can anyone help me out?
Is it because the HttpPost doesn't have a ViewData declared? Thanks for the help.
Since you are Posting on the same View, when you post to Creat the ViewData["Carreras"] is not created. You have to load the data of your carreras again in your Post.
[HttpPost]
public ActionResult Crear(Materia materia, FormCollection values)
{
CarreraRepository carreraRepository = new CarreraRepository();
var carreras = carreraRepository.FindAll().OrderBy(x => x.Nombre);
var carrerasList = new SelectList(carreras, "ID", "Nombre");
ViewData["Carreras"] = carrerasList;
if (ModelState.IsValid)
{
repo.Add(materia);
repo.Save();
return RedirectToAction("Index");
}
return View(materia);
}